将伪锁传递给std :: condition_variable_any :: wait

时间:2015-04-03 18:29:16

标签: c++ multithreading locking language-lawyer condition-variable

假设有三个线程A,B和C. B和C在某一点暂停,等待A发信号通知它们继续。在标准C ++提供的线程同步工具中,std::condition_variable似乎最适合这里(尽管仍然很糟糕)。由于std::condition_variable必须与锁一起使用,因此B和C的代码可能包含以下行:

{
  std::mutex mut;
  std::unique_lock<std::mutex> lock(mut);
  cond_var.wait(lock);  // cond_var is a global variable of type std::condition_variable`
}

请注意,此处使用的mut根本不用于同步目的,只是为了符合std::condition_variable::wait的签名。通过这种观察,我想我们可以通过实现虚拟锁类来做得更好,让我们说dummy_lock,并用std::condition_variable替换std::condition_variable_anydummy_lock满足BasicLockable要求,其所有方法基本上什么都不做。因此,我们得到类似于以下代码:

{
  dummy_lock lock;
  cond_var.wait(lock);  // cond_var is a global variable of type std::condition_variable_any`
}

如果有效,这应该比原来的效率更高。但问题是,根据标准(语言律师在这里适用),它是否真的有效?即使它有效,这绝不是一个优雅的解决方案。那么,你们中的任何人都有更好的想法吗?

2 个答案:

答案 0 :(得分:3)

你正在做一个错误的前提。

互斥锁不仅可以保护条件谓词,还可以保护condition_variable本身。

因此,互斥锁应该与condition_variable在同一范围内,并且所有锁应该锁定相同的互斥锁。

像这样:

// global scope
std::mutex mut;
std::condition_variable cond_var;

// thread scope
{
  std::unique_lock<std::mutex> lock(mut);
  cond_var.wait(lock);
}

见这里:Why do pthreads’ condition variable functions require a mutex?

答案 1 :(得分:0)

你建议的是未定义的行为。关于condition_variable_any的部分引导着,强调我的:

  

Lock类型应符合BasicLockable要求(30.2.5.2)。 [注意:所有标准互斥锁类型   符合这个要求。如果Lock类型不是标准互斥锁类型之一或unique_lock包装器   对于标准互斥类型与condition_variable_any一起使用,用户必须确保任何必要的   关于与condition_variable_any关联的谓词的同步已到位   实例。 -end note]

BasicLockable要求本身并不仅仅描述接口,它们还描述了所需的语义:

  

如果以下表达式格式正确,<{1}}类型符合L要求并且具有   指定的语义(m表示类型L的值)。

     

BasicLockable
  2效果:阻止直到可以为当前执行代理获取锁定。如果抛出异常   然后,不应为当前执行代理获取锁定。

如果您的m.lock()实际上没有获得锁定,则它不是dummy_lock,因此您无法满足BasicLockable的前提。此时,所有投注都已关闭,您不能指望condition_variable_any做任何合理的事情。