Since writing lock-free code is is such a headache-inducer, you're probably best off making some other people suffer the headaches for you. And those other people are the kernel folks, who have developed quite a few lock-free building blocks so you don't have to. For example, there's a collection of functions for manipulating interlocked lists. But today we're going to look at the one-time initialization functions.
The simplest version of the one-time initialization functions isn't actually lock-free, but it does implement the double-checked-lock pattern for you so you don't have to worry about the details. The usage pattern for the InitOnceExecuteOnce function is pretty simple. Here it is in its simplest form:
int SomeGlobalInteger;
BOOL CALLBACK ThisRunsAtMostOnce(
PINIT_ONCE initOnce,
PVOID Parameter,
PVOID *Context)
{
calculate_an_integer(&SomeGlobalInteger);
return TRUE;
}
void InitializeThatGlobalInteger()
{
static INIT_ONCE initOnce = INIT_ONCE_STATIC_INIT;
InitOnceExecuteOnce(&initOnce,
ThisRunsAtMostOnce,
nullptr, nullptr);
}
In the simplest form, you give InitOnceExecuteOnce an INIT_ONCE structure (where it records its state), and a callback. If this is the first time that InitOnceExecuteOnce is called for a particular INIT_ONCE structure, it calls the callback. The callback can do whatever it likes, but presumably it's doing some one-time initialization. If another thread calls InitOnceExecuteOnce on the same INIT_ONCE structure, that other thread will wait until the first thread is finished its one-time execution.
Read more: The Old New Thing
0 comments:
Post a Comment