roybj
roybj

Reputation: 278

CreateMutex with bInitialOwner=true seem to be acting weird

I am really at a loss here. i read the MSDN articles thoroughly but still cant figure out what is going on. my problem is this: when running a few processes with the following code all is working:

HANDLE m = CreateMutex(NULL, FALSE, L"MyMutex");
char c[20] = "2print";
for(int iter = 0; iter<100; ++iter) {
    WaitForSingleObject(m,INFINITE);
    for(int i=0;i<(int)strlen(c);++i) {
           for(int j=0;j<10000;++j)
                 printf("%c",c[i]);
    }
    BOOL ok = ReleaseMutex(m);
}
CloseHandle(m);

that is, the different processes each printing at its own turn and releasing the mutex until all printing is done.

BUT changing the CreateMutex to: (bInitialOwner from FALSE to TRUE)

HANDLE m = CreateMutex(NULL, TRUE, L"MyMutex");

the first creator will not release the mutex! other processes are just sitting there. what amazed me was, that by adding an additional releaseMutex, that is changing:

BOOL ok = ReleaseMutex(m);

into:

BOOL ok = ReleaseMutex(m);
ok = ReleaseMutex(m);

make it work!

i am really confused, why wouldnt the first creator release the mutex correctly? i tried printing all the errors using GetLastError, and what i get seem reasonable, like ERROR_ALREADY_EXISTS for the creators following the first one, which is just what i expect (MSDN says that in this situation the bInitialOwner is simply ignored).

Upvotes: 1

Views: 1757

Answers (1)

bdonlan
bdonlan

Reputation: 231303

When you use bInitialOwner=TRUE, the mutex creator automatically acquires the mutex. Then when you call WaitForSingleObject, it acquired the mutex again. Since win32 mutexes are recursive mutexes, you must release once for each time you acquired the mutex - so two ReleaseMutex calls are needed for the initial creator (however every other thread must only release once!)

You can avoid this by either not using bInitialOwner, or by skipping the WaitForSingleObject on the first loop only if any only if GetLastError() != ERROR_ALREADY_EXISTS. You will need to call SetLastError(0) prior to CreateMutex to clear the error code if you choose the latter.

If you only need bInitialOwner for some kind of initial setup, it will simplify your code if you drop the mutex prior to entering the common loop. Otherwise, I would strongly recommend simply not using bInitialOwner, unless you have a compelling reason to do so.

Upvotes: 4

Related Questions