Friday, October 24, 2014

RunOnce

RunOnce

Sometimes I find my self in a situation where I need to make sure that a piece of code is only executed once.
This is typically some kind of initialization code that must be executed before code that relies on the initialization can execute.

I am pretty sure that we all have seen code that looks similar to this

public class Foo
{
    private bool isInitialized;

    public void DoSomething()
    {
        Initialize();

        // Continue
    }

    private void Initialize()
    {
        if (isInitialized)
        {
            return;
        }

        // Do some initialization code.

        isInitialized = true;
    }
}

Adding thread safety introduces more complexity. The following example uses Double-checked locking.

public class Foo
{
    private bool isInitialized;
    private readonly object lockObject = new object(); 

    public void DoSomething()
    {
        Initialize();

        // Continue
    }

    private void Initialize()
    {
        if (isInitialized)
        {
            return;
        }
        lock (lockObject)
        {
            if (isInitialized)
            {
                return;
            }

            // Do some initialization code.

            isInitialized = true;
        }            
    }
}

The idea here is to wrap this plumbing code into a class that sort of acts as the Lazy<T> class besides the fact that we will not be returning a value.

/// <summary>
/// A thread safe class that ensures that a given 
/// <see cref="Action"/> is only executed once.
/// </summary>
public class RunOnce
{
    private readonly Action action;
    private int hasExecuted;

    /// <summary>
    /// Initializes a new instance of the <see cref="RunOnce"/> class.
    /// </summary>
    /// <param name="action">The <see cref="Action"/> delegate to be executed once.</param>
    public RunOnce(Action action)
    {
        this.action = action;
    }

    /// <summary>
    /// Executes the <see cref="Action"/> only if not already executed.
    /// </summary>
    public void Run()
    {
        if (Interlocked.Exchange(ref hasExecuted, 1) == 0)
        {
            action();
        }
    }       
}    

Once interesting aspect of this class is that it uses no lock to provide thread safety.
The following article explains this in detail.

Now that we have our RunOnce class we can significantly simplify our code.

public class Foo
{
    private RunOnce initializeOnce;

    public Foo()
    {
        initializeOnce = new RunOnce(Initialize);
    }

    public void DoSomething()
    {
        initializeOnce.Run();

        // Continue
    }

    private void Initialize()
    {           
        // Do some initialization code.            
    }
}  

Happy initialization!