将虚拟锁传递给 std::condition_variable_any::等待

Passing a dummy lock to std::condition_variable_any::wait

本文关键字:condition any 等待 variable std 虚拟      更新时间:2023-10-16

假设有三个线程 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_any替换std::condition_variabledummy_lock满足BasicLockable的要求,其所有方法基本上都不做任何事情。因此,我们得到类似于以下内容的代码:

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

如果有效的话,这应该比原来的效率更高。但问题是,它甚至按照标准工作吗(语言律师在这里很合适(?即使它有效,这绝不是一个优雅的解决方案。那么,你们中有人有更好的想法吗?

你正在一个错误的前提下工作。

互斥锁不仅保护条件谓词,还保护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);
}

看这里: 为什么 pthreads 的条件变量函数需要互斥锁?

你的建议是未定义的行为。关于condition_variable_any的部分以强调我的

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

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

BasicLockable L如果以下表达式格式正确且具有 指定的语义(m 表示 L 类型的值(。


m.lock() 2 效果:阻止,直到可以为当前执行代理获取锁。如果引发异常 则不应为当前执行代理获取锁。

如果你的dummy_lock实际上没有获得锁,它就不是BasicLockable,所以你无法满足condition_variable_any的前提。在这一点上,所有的赌注都落空了,你不能指望wait()做任何合理的事情。