使用互斥量作为信号量?

def*_*ode 13 c++ concurrency mutex semaphore c++11

我需要两个线程以"tick tock"模式进行.当使用信号量实现时,这看起来很好:

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 );
   }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我使用互斥锁(在技术上是一个二进制信号量)做同样的事情,它有一个奇怪的代码气味.

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();
   }
}
Run Code Online (Sandbox Code Playgroud)

我认为气味是互斥不是为了将信息传达给另一个线程.(c ++ 11标准委员会添加了一个虚假的try_lock失败来阻止意外的信息传输;§30.4.1/ 14.)似乎互斥体是为了同步对变量的访问,然后可以将信息传递给另一个线程.

最后,当使用a实现时std::condition_variable,它看起来是正确的,但它更复杂(tick_vs_tock变量,互斥锁和条件变量).为简洁起见,我省略了实现,但它确实是直截了当的.

互斥解决方案是否正常?或者它有什么巧妙的错误吗?

有没有一个很好的模式来解决我没有想到的嘀嗒/嘀嗒问题?

Foz*_*ozi 12

Mutex不仅仅是一个二进制信号量,它还有一个限制,即只允许锁定线程解锁它.

你违反了这条规则.

编辑:

来自MSDN:

如果调用线程不拥有互斥对象,则ReleaseMutex函数将失败.

从谷歌出现的一些网站pthread_mutex_unlock:

如果出现以下情况,pthread_mutex_unlock()函数可能会失败:

EPERM当前线程不拥有互斥锁.

您将在其他互斥实现中找到相同的内容.这是有道理的,因为互斥锁应该保护线程对资源的访问权限,因此另一个线程不应该能够解锁它.

  • 我们在这里,30.1.4.2/22:"要求:调用线程应拥有互斥锁".如果没有,那么UB. (2认同)

Ste*_*sop 10

由于您有一个使用信号量的情况,我认为修复是使用互斥锁和条件变量来移植实现一个.

这可能不是特别有效(因为它将使用每个信号量的互斥/ condvar对),但是您可以在具有自己的信号量的系统(例如Posix和Windows)上切换备用实现.

显然,信号量"太容易出错".尽管对Boost充满敬意,但我认为至少我们中的一些人可以管理.当然,你可以把自己绑在试图用多个信号量做复杂事情的结上,而且它们是一个非常低级的工具.但是,当他们是正确的,没有问题.