简体   繁体   中英

Is it OK to lock on System.Collections.Generic.List<t>?

I have been reading about the syncroot element but I can't find it in the List type. So how should the multithreading synchronization be done with the System.Collections.Generic.List<> type?

Why do you want to lock on List<T> as opposed to your specific instance of a list?

It is often suggested that the best method of locking is to lock on a private object created solely for that purpose.

private readonly object myListLock = new object();

// Everywhere you access myList
lock(myListLock)
{
 // do stuff with myList
}

For a great guide to threading in C#, see this Free E-Book (Threading in C#) by Joe Albahari.

The reason you can't find it is because it was explicitly removed . If it is really what you want to do, use a SynchronizedCollection<T> or create a dedicated synchronization object. The best approach (in general) is to create a dedicated synchronization object, as Winston illustrates.

The essential problem with the SyncRoot property is that it provides a false sense of security -- it only handles a very narrow set of circumstances. Developers often neglect synchronization for an entire logical operation, assuming that locking on SyncRoot is good enough.

You generally want to avoid locking on a type ( List<T> in this case). If, for example, you have two instances of your type, or another type were to also use a lock on List<T> , they would all competing for a single global lock. Really, what you are trying to achieve is proper synchronization for a single object.

You have to cast the generic list to an ICollection like this:

using System.Collection; // required for ICollection
using System.Collection.Generic;
List<int> myIntList = new List<int>();
lock (((ICollection)myIntList).SyncRoot)
{
    // do your synchronized stuff here...
}

Keep in mind that this only synchronizes access to the elements of the generic list. It does not synchronize access to the generic list variable, eg, myIntList . If you replace myIntList with a new list at some point, using SyncRoot will not be sufficient. In that case, I would recommend creating a specific synchronization object that can be used for both synchronization scenarios.

The answer is Yes, you can use an instance of the list as a synchronizing object:

private readonly List<string> list = new List<string>();

lock(list)
{
    // ...
}

So you don't have to use SyncRoot property. Moreover, documentation states that

For collections whose underlying store is not publicly available, the expected implementation is to return the current instance.

ie in some cases SyncRoot property returns the collection object itself.

Also read this answer about SyncRoot.

FYI: I've never seen SyncRoot usages in production code. So I suggest you to use instance of any collection as a synchronizing object instead of it's SyncRoot property (as long as the collection is private).

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM