I have a question about locking in c#. Does c# lock an instance of an object, or the member.
If i have the following code:
lock(testVar)
{
testVar = testVar.Where(Item => Item.Value == 1).ToList();
//... do some more stuff
}
Does c# keep the lock, even i set testVar
to a new value?
All C# objects inherit from System.Object
, which itself always contains 4 bytes dedicated to be used when you use the syntactic sugar for lock
. That's called a SyncBlock object.
When you create a new object using new
, in your case, ToList
which generated a new reference to a List<T>
, you're actually overriding the old reference, which invalidates your lock
. That means that now multiple threads could possibly be inside your lock
. The compiler will transform your code into a try-finally
block with an extra local variable, to avoid you from shooting your leg.
That is why the best practice is to define a dedicated private readonly variable which will act as a sync root object, instead of using a class member. That way, your intentions are clear to anyone reading your code.
Edit:
There is a nice article on MSDN which describes the objects structure in memory:
SyncTableEntry also stores a pointer to SyncBlock that contains useful information, but is rarely needed by all instances of an object. This information includes the object's lock, its hash code, any thunking data, and its AppDomain index. For most object instances, there will be no storage allocated for the actual SyncBlock and the syncblk number will be zero. This will change when the execution thread hits statements like lock(obj) or obj.GetHashCode.
It locks on the object that the expression (testVar
) resolves to. This means that your code does have a thread race, because once the list is reassigned, other concurrent threads could be locking on the new instance.
A good rule of thumb: only ever lock
on a readonly
field. testVar
clearly isn't... but it could be, especially if you use RemoveAll
to change the existing list instead of creating a new one. This of course depends on all access to the list happening inside the lock
.
Frankly, though, most code doesn't need to be thread-safe. If code does need to be thread safe, the supported use scenarios must be clearly understood by the implementer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With