Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Languages / C#

Implement Thread Safe One-shot Bool Flag with Interlocked.Exchange()

4.83/5 (4 votes)
4 Dec 2013CPOL3 min read 94.8K  
Wrapping Interlocked.Exchange to mimic a thread safe one-shot bool flag

Introduction

While studying several articles on the C# IDisposable pattern (e.g. Implementing IDisposable and the Dispose Pattern Properly[^]), I was contemplating on the thread safe access of the Dispose() method.

If I have the need to program code that runs exactly once in a multi-threaded environment, there are several approaches. Let's look into some alternatives:

Ignorant Approach

The ignorant approach simply does not care about multi-threading - no good.

Ignorant
C#
bool _called = false;
//...
void Ignorant()
{
    if (!_called)
    {
        _called = true;
        // ...do once... -- maybe not! --
    }
}

Locked Access

These approaches take care of multi-threading issues. But they are both a bit verbose, and one has to not forget setting the lock properly (not to talk forgetting to reset the state so that it cannot be called anymore). This is probably the most common way to do it, which does not mean that it is the best way, though... ;)

Excessive (lock for the whole computation)Smarter (only lock while check-and-set the called state)
C#
bool _called = false;
//...
void ExcessiveLocking()
{
    lock (this)
    {
        if (!_called)
        {
            _called = true;
            // ...do once...
        }
    }
}
C#
bool _called = false;
//...
void SmarterLocking()
{
    bool called = _called;
    lock(this)
    {
        called = _called;
        _called = true;
    }
    if (!called)
    {
        // ...do once...
    }
}

Interlocked.Exchange

This is the less known approach. The uneasy thing is, that there is no Interlocked functions for bool. Not so nice to introduce states for something that is naturally handled by boolean value.

Interlocked with int state
C#
const int NOTCALLED = 0;
const int CALLED = 1;
int _state = NOTCALLED;
//...
void InterlockedCheck()
{
    if (Interlocked.Exchange(ref _state, CALLED) == NOTCALLED)
    {
        // ...do once...
    }
}

ThreadSafeOneShotFlag

First the intended usage:

Explicit callMimic bool
C#
ThreadSafeSingleShotFlag _calledOnce = false;
//...
void SingleShotExplicit()
{
    if (_calledOnce.CheckAndSetFirstCall)
    {
        // ...do once...
    }
}
C#
ThreadSafeSingleShotFlag _calledOnce = false;
//...
void SingleShotMimicBool()
{
    if (!_calledOnce)
    {
        // ...do once...
    }
}

The above code mimics the bool behavior: init by false (= not called yet). And allowing to check and set the called flag. What may be disturbing is the fact that the ! operator not only returns the value, but also sets it. No need to set the value to true within the block. Therefore I provide the explicit access too.

Here goes the code:

C#
/// <summary>Flag-like class that returns at most once the value true.</summary>
/// <example>
/// <code>
/// ThreadSafeSingleShot calledOnce = false;
/// ...
/// if (!calledOnce) // returns with the first call the initial value 
/// and then returns always false
/// {
///    ...
/// }
/// </code>
/// </example>
public class ThreadSafeSingleShotFlag
{
    private static int INIT = 0;
    private static int CALLED = 1;
    private int _state = INIT;
    /// <summary>Explicit call to check and set if this is the first call</summary>
    public bool CheckAndSetFirstCall
    { get { return Interlocked.Exchange(ref _state, CALLED) == INIT;  } }
    
    /// <summary>usually init by false</summary>
    public static implicit operator ThreadSafeSingleShotFlag (bool called)
    {
        return new ThreadSafeSingleShotFlag() { _state = called ? CALLED : INIT };
    }
    /// <summary>if init to false, returns true with the first call, then always false - 
    /// if init to true, always returns false.</summary>
    public static bool operator !(ThreadSafeSingleShotFlag obj)
    {
        return obj.CheckAndSetFirstCall;
    }
}

ThreadSafeSingleShotGuard

Instead of trying to mimic a boolean type (and therefore confusing developers), it might be advised to implement a pure wrapper for the Interlocked.Exchange for a bool. This makes it less vulnerable to unintended use.

First again the intended use:

Mimic Interlocked for bool
C#
ThreadSafeOneShotGuard _guard = ThreadSafeOneShotGuard();
//...
void GuardCheck()
{
    if (_guard.CheckAndSetFirstCall)
    {
        // ...do once...
    }
}

And the respective implementation of the guard class:

C#
/// <summary>
/// Thread safe enter once into a code block:
/// the first call to CheckAndSetFirstCall returns always true,
/// all subsequent call return false.
/// </summary>
public class ThreadSafeSingleShotGuard
{
    private static int NOTCALLED = 0;
    private static int CALLED = 1;
    private int _state = NOTCALLED;
    /// <summary>Explicit call to check and set if this is the first call</summary>
    public bool CheckAndSetFirstCall
    { get { return Interlocked.Exchange(ref _state, CALLED) == NOTCALLED; } }
}

Important Note

The ThreadSafeSingleShotGuard could be used in Dispose pattern, where as the ThreadSafeSingleShotFlag is a bit dangerous: A Dispose() method should never allocate memory. With the ThreadSafeSingleShotFlag, one could use _calledOnce = true;, which would allocate a new object... which is bad. So, don't use the ThreadSafeSingleShotFlag - use ThreadSafeSingleShotGuard instead.

Summary

If Interlocked.Exchange would provide bool support, the whole tip would stop at the respective section above.

This single shot Guard is an attempt to mimic a thread safe one shot flag of the non thread safe form: if (!flag) { flag = true; ... }. It mimics Interlocked.Exchange for bool to ensure that a block is called only once in a multi-threaded environment. If properly used, it could make code more robust. E.g. it could be used in the Dispose pattern to make it thread safe.

C#
ThreadSafeSingleShotGuard _disposeGuard = new ThreadSafeSingleShotGuard();
...
protected virtual void Dispose(bool disposing)
{
   if (_disposeGuard.CheckAndSetFirstCall)
   {
       if (disposing)
       ...
   }
}

I prefer the ThreadSafeSingleShotGuard over the ThreadSafeSingleShotFlag since the guard has less bells and whistles that can cause problems (e.g. no implicit conversion, no surprise in the not-operator (is not a pure function[^] in the given solution of the Flag class), etc.).

Comments are very welcome, especially, how others deal with the issue of not having bool support in the Interlocked class. Which of the above alternatives (or any further) are in real life use?

History

  • V1.0 2012-04-30 Initial version
  • V1.1 2012-04-30 Enhanced summary
  • V1.2 2012-04-30 Add Guard class to replace Flag class to make the solution more robust
  • V1.3 2013-12-04 Fix "Smarter" lock code (thanks to tommy008)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)