call_once for C#

One of the useful gems that made it into C++11 Standard Template Libraries (STD) is call_once, this nifty little method makes sure that specific code is called only once (duh) and it follows these 3 rules:

  • Exactly one execution of exactly one of the functions (passed as f to the invocations in the group) is performed. It is undefined which function will be selected for execution. The selected function runs in the same thread as
    thecall_once invocation it was passed to.
  • No invocation in the group returns before the abovementioned execution of the selected function is completed successfully, that is, doesn’t exit via an exception.
  • If the selected function exits via exception, it is propagated to the caller. Another function is then selected and executed.

I needed something similar – I had a method that should only be called once (initialize) and I wanted to implement something similar to the call_once I’ve been using for my C++ development.
My first object was to try and make it as preferment as possible and so I’ve looked for a solution that does not involve locks:

public static class Call
{
public static void Once(OnceFlag flag, Action action)
{
if (flag.CheckIfNotCalledAndSet)
{
action.Invoke();
}
}
}

since I was  trying to mimic the C++ code I wrote two objects Call (above) and OnceFlag which has all of the magic inside using Interlocked:

public class OnceFlag
{
private const int NotCalled = 0;
private const int Called = 1;
private int _state = NotCalled;
internal bool CheckIfCalledAndSet
{
get
{
var prev = Interlocked.Exchange(ref _state, Called);

return prev == NotCalled;
}
}

internal void Reset()
{
Interlocked.Exchange(ref _state, NotCalled);
}
}

I’m using Interlocked as a thread-safe way to check & set the value making sure that only once it would return true – try it:

class Program
{
static OnceFlag _flag = new OnceFlag();
static void Main(string[] args)
{
var t1 = new Thread(() => DoOnce(1));
var t2 = new Thread(() => DoOnce(2));
var t3 = new Thread(() => DoOnce(3));
var t4 = new Thread(() => DoOnce(4));

t1.Start();
t2.Start();
t3.Start();
t4.Start();

t1.Join();
t2.Join();
t3.Join();
t4.Join();
}

private static void DoOnce(int index)
{
Call.Once(_flag, () => Console.WriteLine("Callled (" + index + ")"));
}
}

It’s very simple solution unfortunately not entirely correct –  the method used will only be called once, but requirements 2 & 3 were not implemented. Luckily for me I didn’t need to make sure that exception enable another call to pass through nor did I need to block other calls until the first call finishes.

But I wanted to try and write a proper implementation, unfortunately not as preferment due to the use of locks:

public static void Once(OnceFlagSimple flag, Action action)
{
lock (flag)
{
if (flag.CheckIfNotCalled)
{
action.Invoke();

flag.Set();
}
}
}

It works, and since I’m already using lock I can split the check and Set methods and use a bool value inside the flag instead of Interlocked.

  • All other threads are blocked due to lock until first finish running – check!
  • In case of exception other method can execute the once block – check!
  • If exited properly the block would only execute once – check!
But not very good performance due to locking on ever time the method gets called.

I’m still looking for a better way to implement call_once – it’s a good exercise in threading and I might find a cool new ways to use the classes under Threading or Task namespaces.

please let me know if you have a better implementation – that’s what the comments are for…

One thought on “call_once for C#

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.