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.
Your
Interlocked.CompareExchangesolution looks the best, and (as you said) is lock-free. It’s also significantly less complicated than other solutions. Locks are quite heavyweight, whereasCompareExchangecan be compiled down to a single CAS cpu instruction. I say go with that one.