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?
With lock
:
public void Foo()
{
lock (fooLock)
{
if (fooCalled) throw new InvalidOperationException();
fooCalled = true;
}
…
}
private object fooLock = new object();
private bool fooCalled;
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.
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.
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.
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.
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