C++ C++;11:为什么std::condition\u变量使用std::unique\u锁?
在使用C++ C++;11:为什么std::condition\u变量使用std::unique\u锁?,c++,multithreading,c++11,mutex,C++,Multithreading,C++11,Mutex,在使用std::condition\u变量时,我对std::unique\u lock的角色有点困惑。据我所知,std::unique_lock基本上是一个膨胀的锁保护,可以在两个锁之间交换状态 到目前为止,我使用了pthread\u cond\u wait(pthread\u cond\u t*cond,pthread\u mutex\u t*mutex)来实现这个目的(我想这就是STL在posix上使用的)。它需要一个互斥锁,而不是锁 这里有什么区别?std::condition\u var
std::condition\u变量时,我对std::unique\u lock
的角色有点困惑。据我所知,std::unique_lock
基本上是一个膨胀的锁保护,可以在两个锁之间交换状态
到目前为止,我使用了pthread\u cond\u wait(pthread\u cond\u t*cond,pthread\u mutex\u t*mutex)
来实现这个目的(我想这就是STL在posix上使用的)。它需要一个互斥锁,而不是锁
这里有什么区别?std::condition\u variable
处理std::unique\u lock
这一事实是否是一种优化?如果是这样的话,它到底有多快?这本质上是一个API设计决策,在默认情况下使API尽可能安全(额外的开销可以忽略不计)。通过要求传递唯一锁
而不是原始的互斥锁
,API用户将被引导编写正确的代码(在存在异常的情况下)
近年来,C++语言的焦点已经转向了默认的安全性(但是如果用户愿意和努力的话,仍然允许用户自己射击)。
所以没有技术上的原因
我对cmeerw的答案投了赞成票,因为我相信他给出了一个技术上的理由。让我们走过去。让我们假设委员会决定让条件变量
等待互斥锁
。下面是使用该设计的代码:
void foo()
{
mut.lock();
// mut locked by this thread here
while (not_ready)
cv.wait(mut);
// mut locked by this thread here
mut.unlock();
}
这正是不应该使用条件变量的方法。在标有以下标记的区域:
// mut locked by this thread here
存在异常安全问题,这是一个严重的问题。如果在这些区域(或通过cv.wait
本身)引发异常,则互斥锁的锁定状态将泄漏,除非还将try/catch放在某个位置以捕获异常并将其解锁。但这只是要求程序员编写的更多代码
假设程序员知道如何编写异常安全代码,并且知道如何使用unique\u lock
来实现它。现在代码如下所示:
void foo()
{
unique_lock<mutex> lk(mut);
// mut locked by this thread here
while (not_ready)
cv.wait(*lk.mutex());
// mut locked by this thread here
}
这段代码非常简单李>
它是异常安全的
wait
函数可以检查lk.owners\u lock()
并在异常为false
时抛出异常
这些是推动条件变量
的API设计的技术原因
另外,condition\u variable::wait
不接受lock\u guard
,因为lock\u guard
是这样说的:我拥有这个互斥锁,直到lock\u guard
销毁。但是当您调用条件变量::wait
时,会隐式释放互斥锁。因此,该操作与lock\u guard
用例/语句不一致
无论如何,我们需要unique\u lock
,这样就可以从函数返回锁,将它们放入容器中,并以异常安全的方式在非作用域模式中锁定/解锁互斥锁,因此unique\u lock
是条件变量::wait
的自然选择
更新
bamboon在下面的评论中建议我对比条件变量\u any
,因此:
问题:为什么不将条件变量::wait
模板化,以便我可以将任何可锁定的
类型传递给它
回答:
这是非常酷的功能。例如,演示了在条件变量的共享模式下等待共享锁
(rwlock)的代码(posix世界中闻所未闻,但非常有用)。但是,功能更昂贵
因此,委员会推出了一种具有此功能的新型:
`condition_variable_any`
使用此条件变量
适配器,您可以等待任何可锁定类型。如果它有成员lock()
和unlock()
,您就可以开始了。condition\u variable\u any
的正确实现需要一个condition\u variable
数据成员和一个shared\u ptr
数据成员
因为这个新功能比基本的条件变量::wait
更昂贵,而且条件变量
是一个低级工具,这个非常有用但更昂贵的功能被放在一个单独的类中,因此只有在您使用它时才需要付费。您是否对为什么需要带条件变量的锁/互斥锁、锁和互斥锁之间的区别或者为什么条件变量使用唯一的锁而不是互斥锁感到困惑?“为什么条件变量使用唯一锁而不是互斥锁”这句话。所以没有技术上的原因?你能澄清一下“它”吗“。您是在谈论锁紧保护
,还是条件变量
,或者可能是条件变量::等待
?对不起,忘了它。我完全忘记了condition\u variable\u any
Ah,模板condition\u variable::wait
。是的,condition\u variable\u any
是一个不错的选择。功能没有被折叠到条件变量中的原因是它更昂贵。而condition\u variable
是一个非常低级的工具,它需要尽可能高效。如果您使用条件变量\u any
,您只需为添加的功能付费。好的,谢谢您提供的额外信息。也许可以在你的答案中加上这一点,因为人们可能会用一个简单的互斥锁误用条件变量。\u any
。哇,我被你的答案吓坏了。非常感谢您提供如此详细的信息!
`condition_variable_any`