问题
By lock helpers I am referring to disposable objects with which locking can be implemented via using
statements. For example, consider a typical usage of the SyncLock
class from Jon Skeet's MiscUtil:
public class Example
{
private readonly SyncLock _padlock;
public Example()
{
_padlock = new SyncLock();
}
public void ConcurrentMethod()
{
using (_padlock.Lock())
{
// Now own the padlock - do concurrent stuff
}
}
}
Now, consider the following usage:
var example = new Example();
new Thread(example.ConcurrentMethod).Start();
My question is this - since example
is created on one thread and ConcurrentMethod
is called on another, couldn't ConcurrentMethod
's thread be oblivious to _padock
's assignment in the constructor (due to thread caching / read-write reordering), and thus throw a NullReferenceException
(on _padLock
itself) ?
I know that locking with Monitor
/lock
has the benefit of memory barriers, but when using lock helpers such as these I can't see why such barriers are guaranteed. In that case, as far as I understand, the constructor would have to be modified:
public Example()
{
_padlock = new SyncLock();
Thread.MemoryBarrier();
}
Source: Understanding the Impact of Low-Lock Techniques in Multithreaded Apps
EDIT Hans Passant suggests that the creation of a thread implies a memory barrier. So how about:
var example = new Example();
ThreadPool.QueueUserWorkItem(s => example.ConcurrentMethod());
Now a thread is not necessarily created...
回答1:
No, you do not need to do anything special to guarentee that memory barriers are created. This is because almost any mechanism used to get a method executing on another thread produces a release-fence barrier on the calling thread and an aquire-fence barrier on the worker thread (actually they may be full fence barriers). So either QueueUserWorkItem
or Thread.Start
will automatically insert the necessary barriers. Your code is safe.
Also, as a matter of tangential interest Thread.Sleep
also generates a memory barrier. This is interesting because some people naively use Thread.Sleep
to simulate thread interleaving. If this strategy were used to troubleshoot low-lock code then it could very well mask the problem you were trying to find.
来源:https://stackoverflow.com/questions/6574389/thread-safe-usage-of-lock-helpers-concerning-memory-barriers