Use a mutex as a semaphore?
Asked Answered
B

3

16

I need two threads to progress in a "tick tock" pattern. When implmented with a semaphore this looks fine:

Semaphore tick_sem(1);
Semaphore tock_sem(0);

void ticker( void )
{
   while( true )
   {
      P( tick_sem );
      do_tick();
      V( tock_sem );
   }
}

void tocker( void )
{
   while( true )
   {
      P( tock_sem );
      do_tock();
      V( tick_sem );
   }
}

However, if I do the same thing with a mutex ( which is technically a binary semaphore ), it has an odd code smell.

std::mutex tick_mutex;
std::mutex tock_mutex;
tock_mutex.lock();

void ticker( void )
{
   while( true )
   {
      tick_mutex.lock();
      do_tick();
      tock_mutex.unlock();
   }
}

void tocker( void )
{
   while( true )
   {
      tock_mutex.lock()
      do_tock();
      tick_mutex.unlock();
   }
}

I think the smell is that a mutex isn't meant to convey information to another thread. (The c++11 standard committee added a spurious fail to try_lock to defeat unexpected information transfer; §30.4.1/14.) It seems like mutexes are meant to synchronize access to a variable, which can then convey information to another thread.

Lastly, when implemented with a std::condition_variable, it looks correct but it's more complicated ( a tick_vs_tock variable, a mutex, and a condition variable). I've omitted the implementation for brevity, but it's really straight forward.

Is the mutex solution fine? Or is there something subtly wrong with it?

Is there a good pattern for solving my tick/tock problem that I haven't thought of?

Bet answered 23/7, 2011 at 23:51 Comment(3)
BTW: this issue only arose because C++0x doesn't have a std::semaphore and the double std::mutex solution is less complicated than the std::condition_variable solution.Bet
(Why) is it even valid to unlock() a mutex in a thread that doesn't currently hold it?Nessim
@Steve that is really good question (hint, hint, nudge, nudge).Bet
E
15

A Mutex is not simply just a binary semaphore, it also has the limitation that only the locking thread is allowed to unlock it.

You are breaking that rule.

Edit:

From MSDN:

The ReleaseMutex function fails if the calling thread does not own the mutex object.

From some site that google turned up for pthread_mutex_unlock:

The pthread_mutex_unlock() function may fail if:

EPERM The current thread does not own the mutex.

And you will find the same on other mutex implementations. It makes sense because a mutex is supposed to guard a thread's access to a resource, so another thread should not be able to unlock it.

Ephesian answered 24/7, 2011 at 0:10 Comment(4)
As per Steve's comment. Is that really a rule? It's definitely a good idea.Bet
@deft - I think it depends on the implementation of the mutex, which is system-dependent. It is generally not a good idea to unlock someone else's mutex, even if it is allowed by the system.Immunotherapy
@deft_code: I haven't read the mutex section of the FDIS yet, but I'd be astonished if it isn't a rule. Mutexes have an owner, it's part of their fundamental definition as a synchronization tool.Nessim
Here we are, 30.1.4.2/22: "Requires: the calling thread shall own the mutex". So UB if it doesn't.Nessim
N
11

Since you have a case to use a semaphore, I think the fix is to portably implement one using a mutex and a condition variable.

This might not be especially efficient (since it'll use a mutex/condvar pair per semaphore), but you can switch in an alternate implementation on systems that have their own semaphores (such as Posix and Windows).

Apparently semaphores are "too error-prone". With all due respect to Boost, I think at least some of us can manage. Certainly you can tie yourself in knots trying to do complicated things with multiple semaphores, and they are a pretty low-level tool. But when they're the right thing, no problem.

Nessim answered 24/7, 2011 at 0:15 Comment(1)
I agree that the "too error prone" thing is weird. Mutexes can be error prone too. So can a hammer.Concave
B
-2

Hm, have you understood the whole point of the Mutex? It's clearly unwise to release one mutex and lock the other.

Banger answered 8/5 at 13:46 Comment(1)
Hello Cay. Thanks for taking the time to answer this question. For future reference it might be better to add comments like this as a comment under the question, rather than as an answer. If you look at the other two answers to this question, they give a lot more information around the subject. Cheers, Mike (moderating new answers).Fries

© 2022 - 2024 — McMap. All rights reserved.