Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Thread safe usage of lock helpers (concerning memory barriers)

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...

like image 874
Ohad Schneider Avatar asked Jul 04 '11 17:07

Ohad Schneider


People also ask

How are memory barriers implemented?

Memory barrier is implemented by the hardware processor. CPUs with different architectures have different memory barrier instructions. Therefore, the programmer needs to explicitly call memory barrier in the code to solve the preceding problem.

What is memory barrier in operating system?

In computing, a memory barrier, also known as a membar, memory fence or fence instruction, is a type of barrier instruction that causes a central processing unit (CPU) or compiler to enforce an ordering constraint on memory operations issued before and after the barrier instruction.

What is fencing in programming?

Fencing is the process of isolating a node of a computer cluster or protecting shared resources when a node appears to be malfunctioning.


1 Answers

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.

like image 87
Brian Gideon Avatar answered Dec 02 '22 06:12

Brian Gideon