【问题标题】:Condition variable waiting on multiple mutexes条件变量在多个互斥体上等待
【发布时间】:2016-12-23 17:56:11
【问题描述】:

我有一个std::condition_variable_any,它等待一个自定义锁,该锁由两个互斥锁(一个std::mutex 和一个共享锁定std::shared_mutex)组成。它的unlock() 操作只是按顺序解锁两个互斥锁。

例如(伪代码):

mutex mutex1;
shared_mutex mutex2;
condition_variable_any cv;
// acquiring the locks
DualLock lock(unique_lock(mutex1), shared_lock(mutex2));
// waiting
cv.wait(lock);

cv.wait() 应该原子地解锁mutex1mutex2,并让线程休眠直到cv 得到通知。

一旦mutex1mutex2 中的任何一个被解锁,它仍然保证线程正在睡眠并监听条件变量通知?

或者是否有可能一个互斥锁被解锁,第二个线程锁定它,发送通知,但第一个线程还没有休眠和监听。所以通知永远不会到达,也不会发生唤醒。

【问题讨论】:

  • 如果DualLock 不使用std::lock 来锁定互斥锁,你就有死锁的危险。您的伪代码看起来在构造 DualLock 的行中面临死锁的危险。

标签: c++ multithreading c++11 mutex condition-variable


【解决方案1】:

如果DualLock 满足BasicLockable 的要求,那么代码将按预期执行。如果没有,就不会。

BasicLockable 引用是here

所以通知永远不会到达,也不会发生唤醒。

如果条件变量使用得当,这种情况永远不会发生。条件变量的唤醒不能解释为事件的信号,因为 condition_variable 的文档说明可能存在虚假唤醒。

通知充其量只是表明现在可能是测试您正在等待的条件的好时机(并且您可以在知道测试受互斥体保护的安全知识的情况下这样做)。

当前线程的条件状态和阻塞状态是两个独立的关注点。

这是一个更好的例子(假设 DualLock 正确地模拟了 BasicLockable):

bool condition_met = false;

mutex mutex1;
shared_mutex mutex2;
condition_variable_any cv;
// acquiring the locks
DualLock lock(unique_lock(mutex1), shared_lock(mutex2));
while(!condition_met)
{
    // waiting
    cv.wait(lock);
}
// whatever happens, you have the lock here

// ...work

lock.unlock();

您的通知程序会这样通知:

DualLock lock(unique_lock(mutex1), shared_lock(mutex2));
condition_met = true;
lock.unlock();     // note the order: unlock mutex first...
cv.notify_all();   // ...then notify the condition variable

【讨论】:

  • 所以如果cv.notify_all() 被调用,而cv.wait() -> DualLock::unlock() 仍在等待线程上执行(在它只解锁了两个互斥锁之一之后),仍然可以保证wait 不会开始睡觉,而是立即返回?
  • @tmlen 自定义互斥锁的锁定方法必须按照概念运行(即完全锁定互斥锁、阻止它们或抛出异常)。如果你做对了,上面的代码将永远有效。这里的复杂之处在于双锁的实现,而不是 cv。
猜你喜欢
  • 2018-03-09
  • 1970-01-01
  • 2015-07-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-30
  • 2018-05-17
  • 2020-01-10
相关资源
最近更新 更多