使用互斥锁作为信号量?
我需要两个线程以“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 );
}
}
但是,如果我使用互斥锁(技术上是二进制信号量)做同样的事情,它就会有一种奇怪的代码味道。
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();
}
}
我认为气味是互斥体并不意味着将信息传递给另一个线程。 (c++11 标准委员会添加了一个虚假的 try_lock 失败来阻止意外的信息传输;§30.4.1/14。)互斥体似乎是为了同步对变量的访问,然后变量可以将信息传递到另一个线程。
最后,当使用 std::condition_variable 实现时,它看起来是正确的,但它更复杂(tick_vs_tock 变量、互斥体和条件变量)。为了简洁起见,我省略了实现,但它确实很简单。
互斥解决方案好吗?或者其中有什么微妙的错误吗?
有没有一个好的模式可以解决我没有想到的滴答/滴答问题?
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?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
互斥体不仅仅是一个二进制信号量,它还有一个限制,即只有锁定线程才可以解锁它。
你违反了这条规则。
编辑:
来自MSDN:
从 Google 发现的 pthread_mutex_unlock 的某个网站:
您会在其他互斥锁实现上发现同样的情况。这是有道理的,因为互斥体应该保护线程对资源的访问,因此另一个线程不应该能够解锁它。
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:
From some site that google turned up for pthread_mutex_unlock:
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.
由于您有使用信号量的情况,我认为解决方法是可移植 使用互斥体和条件变量实现一个。
这可能不是特别有效(因为它将为每个信号量使用互斥体/条件变量对),但您可以在拥有自己的信号量的系统(例如 Posix 和 Windows)上切换替代实现。
显然 信号量“太容易出错” ”。尽管对 Boost 抱有应有的尊重,但我认为至少我们中的一些人可以做到这一点。当然,您可能会陷入困境尝试使用多个信号量完成复杂的事情,它们是一个相当低级的工具。但当它们是正确的时候,就没问题了。
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.
嗯,你明白 Mutex 的全部意义了吗?
释放一个互斥体并锁定另一个互斥体显然是不明智的。
Hm, have you understood the whole point of the Mutex?
It's clearly unwise to release one mutex and lock the other.