I'm curious about the difference below two example.
case 1) locking by readonly object
private readonly object key = new object();
private List<int> list = new List<int>;
private void foo()
{
lock(key){
list.add(1);
}
}
case2) locking by target object itself
private List<int> list = new List<int>;
private void foo()
{
lock(list){
list.add(1);
}
}
are both cases thread-safe enough? i'm wondering if garbage collector changes the address of list
variable(like 0x382743 => 0x576382) at sometime so that it could fail thread-safe.
A lock can be locked using the acquire() method. Once a thread has acquired the lock, all subsequent attempts to acquire the lock are blocked until it is released. The lock can be released using the release() method.
A Lock object can not be acquired again by any thread unless it is released by the thread which is accessing the shared resource. An RLock object can be acquired numerous times by any thread. A Lock object can be released by any thread. An RLock object can only be released by the thread which acquired it.
The lock statement acquires the mutual-exclusion lock for a given object, executes a statement block, and then releases the lock. While a lock is held, the thread that holds the lock can again acquire and release the lock. Any other thread is blocked from acquiring the lock and waits until the lock is released.
So long as List<T>
does not have within its code any lock(this)
statements the two functions will behave the same.
However, because you don't always know if a object locks on itself or not without looking through it's source code it is safer to just lock on a separate object.
One thing of note, classes that inherit from ICollection
have a SyncRoot
property which is explicitly the object you are supposed to lock on if you want to put a lock on the collection without using a seperate object.
private List<int> list = new List<int>;
private void foo()
{
lock(((ICollection)list).SyncRoot){
list.add(1);
}
}
This internally is just doing the same thing as you did and created a separate new Object()
to lock on.
In both cases, foo() is thread-safe. But locking on separate readonly object (case 1) is preferred, because
List<T>
to list could cause some troubles, e.g. loss of atomicity of locked block of code)Lock is guaranteed to work properly even if garbage collector moves object you are locking on.
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