Every once in a while, you need to make sure a function is called exactly once. This is useful for initialization code for example. The concept is similar to a local static, but local statics are not thread safe. It is possible two threads might try to construct a local static at once, before the initialization flag gets set.
Metrowerks::mutex& get_mutex() { static Metrowerks::mutex mut; // ??!!!! return mut; }
If more than one thread can call get_mutex() for the first time, at the same time, then it is possible that two threads may try to construct mut (and this would be bad). There are a couple of ways to deal with this problem.
You could make mut a global. But that may give you an undefined order of construction among global objects that is unacceptable for your application's start up code.
You could call get_mutex() once before you create any threads:
int main()
{
get_mutex(); // just initialize the local static
}
Now it is safe to call get_mutex() from multiple threads as the construction step is already done.
Simple, but a little ugly. And you may not have control over main (what if you're writing a library?).
Enter Metrowerks::call_once. You can use call_once to ensure that only one thread calls get_mutex for the first time. The prototype for call_once looks like:
void call_once(void (*func)(), once_flag& flag);
Metrowerks::once_flag is the type of flag that you must initialize (at link time) to the macro: _EWL_THREAD_ONCE_INIT.
If call_once is called with such a flag, it will atomically execute the function, and set the flag to some other value. All other threads attempting to call call_once will block until the first call returns. Later threads calling into call_once with the same flag will return without doing anything. Here is how you could use it to "initialize" get_mutex().
Metrowerks::mutex& get_mutex_impl() { static Metrowerks::mutex mut; return mut; } void init_get_mutex() { get_mutex_impl(); } Metrowerks::once_flag init_get_mutex_flag = _EWL_THREAD_ONCE_INIT; Metrowerks::mutex& get_mutex() { Metrowerks::call_once(init_get_mutex, init_get_mutex_flag); return get_mutex_impl(); }
The first thread into get_mutex will also go into call_once while blocking other threads from getting past that point. It then constructs the static mutex at its leisure. Once it returns, then threads can have unfettered access to the fully constructed static mutex.
call_once works identically in single thread mode.