win32: Threadsafe initialization of mutexes
The $64-question: is the following function thread safe?
static HANDLE mutex=0; void lock(void) { if (mutex==0) mutex=CreateMutex(0, FALSE, 0); WaitForSingleObject(mutex, INFINITE); } void unlock(void) { ReleaseMutex(mutex); } void foo(void) { lock(); do_something(); unlock(); }
foo() is called by several threads. foo creates a mutex, if it wasn’t yet created, locks it, does something and then unlocks the mutex.
The dangerous code is in lock(), when the mutex is created. When two threads call the function simultaneously, and the mutex handle is NULL, both threads create their own mutex, instead of using the same mutex. And then both threads call do_something() in parallel. (This is not just a theoretical case – it has happened in an application i wrote, and it was a reproducable bug.)
To avoid this problem (which actually happened to me a few weeks ago), we have to synchronize the call to CreateMutex(). There are several options, but the fastest should be an atomic “test-and-modify” operation. The win32 SDK offers a function called InterlockedCompareExchangePointer(). It tests, if a pointer has a certain value; if yes, the pointer is exchanged with another value. Here is the new code for lock():
void lock(void) { if (mutex==0) { HANDLE mutex2=CreateMutex(0, FALSE, 0); InterlockedCompareExchangePointer(&mutex, mutex2, NULL); if (mutex!=mutex2) CloseHandle(mutex2); } }
If the mutex was not yet created, we create a second (temporary) mutex mutex2. InterlockedCompareExchangePointer() replaces mutex with mutex2, but only if mutex is NULL (the third parameter). Otherwise, we release mutex2, to avoid a resource leak.
Since InterlockedCompare-functions use atomic CPU opcodes, the “compare and exchange” will not be interrupted.
On linux this problem doesn’t exist – pthread-mutexes can be initialized statically:
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
But that’s impossible for win32 handles, since they are pointers to pointers, and therefore have to be allocated at runtime.
Hi,
on Window you can use some #pragma directives. These functions gonna be called once at startup and shutdown of your application.
A similar way is available with gcc. search for “__attribute__ ((constructor))” or “__attribute__ ((destructor))”
static HANDLE mutex=0;
static void InitMutex()
{
mutex=CreateMutex(0, FALSE, 0);
}
static void DeInitMutex()
{
}
#pragma startup InitMutex
#pragma shutdown DeInitMutex
That’s a nice idea, thanks. This reminds me of a gcc behaviour upon parsing the “#pragma”-directive. Since pragmas are “implementation defined”, according to the C standard, gcc 1.34 started random games from /usr/bin/games…