views:

67

answers:

4

If I have multiple threads calling the Add method of a List object, and no readers, do I only need to lock on the List object before calling Add to be thread safe?

A: 

Yes, you need to lock. Instance methods are not guaranteed to be thread safe on List<T>.

Brian Rasmussen
+1  A: 

Yes. But you might also consider subclassing the List and "new" over the Add method. That will allow you to encapsulate the lock. It will work great as long as nothing accesses the base List. This technique is used for simple tree structures in XNA video games.

Brent Arias
A: 

I think these have been linked before on here, but I found them to be very useful and interesting:

Thread safe collections are hard

Thread safe collection

daft
+2  A: 

Usually it's best to lock on a separate (immutable) object... locking on the same object you're modifying is bad practice should be done with caution.

private readonly object sync = new object();
private List<object> list = new List<object>();

void MultiThreadedMethod(object val)
{
    lock(sync)
    {
        list.Add(val);
    }
}

In a basic case like this you will not have a problem, but if there is a possibility that your list can be changed (not the contents of the list, but the list itself), then you might have a situation where you lock on two objects when you only intend to lock on one.

Lirik
This is not exactly true. What is bad practice is locking on an object which is publicly exposed to other code to lock on. If this collection is shared, then, yes, it's bad practice to lock on it since other code could then lock you out. However, if the collection is completely contained by you, then you can make the call if it's a good candidate to sync on.
codekaizen
@codekaizen: Note that you don't know what the code *within List* will do... maybe it will leak the reference. You're right in saying that this answer isn't quite right though: the point about using a private object isn't about immutability (you'll still lock on the same monitor even if the data inside it changes). It's about whether any other code has access to the same monitor and might lock on it themselves.
Jon Skeet
@codekaizen, well "bad practice" is a strong label, but I guess the point is that locking on the same object should be done with *caution*.
Lirik
@Jon, I agree it is good defensive practice to not lock on something you don't know the scope of the references to (I always lock on a separate Object() instance). Perhaps it's nitpicking, but I'm happy to be able to dive into the .Net reference source with even the merest hint of need, and it doesn't appear that the `this` pointer is ever passed out of the class, except for Enumerator and ReadOnlyCollection, and those don't pass the reference out. Surely this kind of hair-splitting is why MS releases the .Net reference source!
codekaizen
@codekaizen: The current version may not. Are you willing to bet it never has and it never will though?
Jon Skeet
@Jon, it's v4.0 (Source\.Net\4.0\DEVDIV_TFS\Dev10\Releases\RTMRel\ndp\clr\src\BCL\System\Collections\Generic\List.cs\1305376\List.cs). However, I am not willing to take that bet, and will stick with the defensive practice...
codekaizen