C 11:为什么std :: condition_variable使用std :: unique_lock?

我有点困惑的std :: unique_lock的作用时使用std :: condition_variable的作用。据我理解的documentation,std :: unique_lock基本上是一个blo肿的锁保护,有可能交换两个锁之间的状态。

我到目前为止使用pthread_cond_wait(pthread_cond_t * cond,pthread_mutex_t * mutex)(我猜这是STL在posix上使用的)。它需要一个互斥,而不是一个锁。

这里有什么区别?是事实std :: condition_variable处理std :: unique_lock优化?如果是这样,它是如何更快?

最佳答案

so there is no technical reason?

我upvote cmeerw的答案,因为我相信他给了一个技术原因。让我们通过它。让我们假装委员会已经决定有一个互斥体的condition_variable等待。这里是使用该设计的代码:

void foo()
{
    mut.lock();
    // mut locked by this thread here
    while (not_ready)
        cv.wait(mut);
    // mut locked by this thread here
    mut.unlock();
}

这正是如何不应该使用condition_variable。在标有:

// mut locked by this thread here

有一个异常安全问题,这是一个严重的问题。如果在这些区域(或通过cv.wait本身)抛出异常,互斥体的锁定状态将被泄漏,除非try / catch也被放在某处以捕获异常并将其解锁。但这只是更多的代码,你要求程序员写。

让我们说程序员知道如何编写异常安全代码,并知道使用unique_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
}

这是更好的,但它仍然不是一个伟大的情况。 condition_variable接口正在使程序员走出他的方式来让东西工作。如果lk偶然不引用互斥体,则存在可能的空指针解引用。并且没有办法为condition_variable ::等待检查这个线程是否拥有mut的锁。

哦,只是记住,还有一个危险,程序员可能选择错误的unique_lock成员函数来暴露互斥体。 * lk.release()在这里是灾难性的。

现在让我们看看代码是如何用实际的condition_variable API编写的,该API需要一个unique_lock< mutex&gt ;:

void foo()
{
    unique_lock<mutex> lk(mut);
    // mut locked by this thread here
    while (not_ready)
        cv.wait(lk);
    // mut locked by this thread here
}

>这段代码很简单,可以得到。
>它是异常安全。
>等待函数可以检查lk.owns_lock(),如果它为false则抛出异常。

这些是驱动condition_variable的API设计的技术原因。

另外,condition_variable :: wait不采取lock_guard< mutex>因为lock_guard< mutex>是怎么说的:我拥有这个互斥锁的锁,直到lock_guard< mutex>破坏。但是当你调用condition_variable :: wait时,你隐式释放互斥锁。因此,操作与lock_guard用例/语句不一致。

我们需要unique_lock反之,以便可以从函数返回锁,将它们放入容器,并以异常安全方式锁定/解锁非作用域模式中的互斥锁,因此unique_lock是condition_variable :: wait的自然选择。

更新

bamboon在下面的评论中建议我对比condition_variable_any,所以这里:

问题:为什么不是condition_variable ::等待模板,以便我可以传递任何Lockable类型呢?

回答:

这是真的很酷的功能。例如,this paper演示了在共享模式下对条件变量(在posix世界中前所未闻,但非常有用)上等待shared_lock(rwlock)的代码。然而,功能更昂贵。

因此,委员会引入了一种具有此功能的新类型:

`condition_variable_any`

使用这个condition_variable适配器可以等待任何可锁定的类型。如果它有成员lock()和unlock(),你是好去。 condition_variable_any的正确实现需要condition_variable数据成员和shared_ptr< mutex>数据成员。

因为这个新的功能比你的基本condition_variable :: wait更昂贵,而且因为condition_variable是一个低级别的工具,这个非常有用但更昂贵的功能被放入一个单独的类,所以如果你使用它只支付它。

转载注明原文:C 11:为什么std :: condition_variable使用std :: unique_lock? - 代码日志