Windows synchronization on multiple mutexes

548 views Asked by At

I'm not clear about this, can someone confirm this for me?

I have the following synchronization issue. I have the following objects:

A. Process 1, thread 1: Read & write access to the resource.
B. Process 1, thread 2: Read access to the resource.
C. Process 2, thread 3: Read access to the resource.

And here's the access conditions:

  1. A must be blocked while B or C are on.
  2. B must be blocked only while A is on.
  3. C must be blocked only while A is on.

So I thought to use 2 named mutexes for that:

  • hMutex2 = used to satisfy condition 2 above.
  • hMutex3 = used to satisfy condition 3 above.
  • hStopEvent = a stop event (needs to stop the thread if the app is closing).

So for A:

HANDLE hHandles[3] = {hMutex2, hMutex3, hStopEvent};
DWORD dwRes = WaitForMultipleObjects(3, hHandles, FALSE, INFINITE);
if(dwRes == WAIT_OBJECT_0 + 2)
{
    //Quit now
    return;
}
else if(dwRes == WAIT_OBJECT_0 + 0 ||
    dwRes == WAIT_OBJECT_0 + 1)
{
    //Do reading & writing here
    ...

    //Release ownership
    ReleaseMutex(hMutex2);
    ReleaseMutex(hMutex3);
}
else
{
    //Error
}

For B:

DWORD dwRes = WaitForSingleObject(hMutex2, INFINITE);
if(dwRes == WAIT_OBJECT_0)
{
    //Do reading here
    ...

    //Release ownership
    ReleaseMutex(hMutex2);
}
else
{
    //Error
}

For C:

DWORD dwRes = WaitForSingleObject(hMutex3, INFINITE);
if(dwRes == WAIT_OBJECT_0)
{
    //Do reading here
    ...

    //Release ownership
    ReleaseMutex(hMutex3);
}
else
{
    //Error
}

Can someone confirm this:

  • When calling WaitForMultipleObjects on both mutexes, do they both become signaled (or blocked)?
  • Also do I needs to release both mutexes?
3

There are 3 answers

4
xtofl On

As a matter of fact, I can contradict it. WaitForMultipleObjects with the waitAll parameter set to FALSE will return if any of the objects are signaled. Here's the documentation :) Set it to TRUE and you'll have it waiting for all objects.

Your solution doesn't scale well, though: add another reading thread, and you're stuck with a third mutex...

The Writer/Readers problem has been solved many times before, however; why not take a look into existing implementations? Will save you a lot of debug time, especially if you're not yet familiar with the windows synchronization API. (Teaser: posix threads have a readwritelock, boost has a shared_mutex.)

3
Mark Wilkins On

The WaitForMultipleObjects call as written (FALSE for the 3rd parameter) will return when any one of the mutexes is signaled. This means that both the writer and one of the readers could obtain simultaneous access to the resource. One reader could be accessing the resource while the other reader releases its mutex. At that point, the writer would be released.

So to use both mutexes like that, you would need to wait on both of them. However, you cannot just set that third parameter to TRUE since it would mean that it would require hStopEvent to also be signaled in order to release that thread (which is obviously not desired).

One possibility might be to check which mutex was released and then have the writer wait for the other one as well before continuing. Then it would need to release both of them after finishing its task. A problem with this type of solution is that it can start getting complex in a hurry and if you add more processes that need the mutexes, you can end up with deadlock if you are not careful. Using a reader-writer type of lock would simplify the processing quite a bit.

Edit This is not really part of the answer to the question, but depending on the processes involved and how often they will access the resource and how long they will hold the mutex while accessing it, you could really simplify it by using one mutex and just treating it as a critical section ... each process gets it when it needs access to the resource. It of course would not allow both reader threads/processes to have concurrent access, though, so that may or may not be acceptable. But it is a lot easier to verify in the long run.

0
Greg On

What you are looking for is reader-writer lock. In your algorithm there is one serious problem - starvation of process A: if B and C keeps working and taking their mutexes, A might be unable to enter.