Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to: Write a thread-safe method that may only be called once?

I'm attempting to write a thread-safe method which may only be called once (per object instance). An exception should be thrown if it has been called before.

I have come up with two solutions. Are they both correct? If not, what's wrong with them?

  1. With lock:

    public void Foo()
    {
        lock (fooLock)
        {
            if (fooCalled) throw new InvalidOperationException();
            fooCalled = true;
        }
        …
    }
    private object fooLock = new object();
    private bool fooCalled;
    
  2. With Interlocked.CompareExchange:

    public void Foo()
    {
        if (Interlocked.CompareExchange(ref fooCalled, 1, 0) == 1)
            throw new InvalidOperationException();
        …
    }
    private int fooCalled;
    

    If I'm not mistaken, this solution has the advantage of being lock-free (which seems irrelevant in my case), and that it requires fewer private fields.

I am also open to justified opinions which solution should be preferred, and to further suggestions if there's a better way.

like image 622
stakx - no longer contributing Avatar asked Mar 01 '12 10:03

stakx - no longer contributing


People also ask

How might you ensure that only one thread at a time executes a particular method?

The synchronized keyword can be used to ensure that only one thread at a time executes a particular section of code. This is a simple way to prevent race conditions, which occur when several threads change shared data at the same time in a way that leads to incorrect results.

What makes a method thread-safe?

So, it's considered to be thread-safe and can be safely called by multiple threads at the same time. All threads can safely call the factorial() method and will get the expected result without interfering with each other and without altering the output that the method generates for other threads.


1 Answers

Your Interlocked.CompareExchange solution looks the best, and (as you said) is lock-free. It's also significantly less complicated than other solutions. Locks are quite heavyweight, whereas CompareExchange can be compiled down to a single CAS cpu instruction. I say go with that one.

like image 181
thecoop Avatar answered Oct 10 '22 12:10

thecoop