【问题标题】:Why does a condition variable need a lock (and therefore also a mutex) [duplicate]为什么条件变量需要锁(因此也需要互斥锁)[重复]
【发布时间】:2015-05-12 14:52:25
【问题描述】:

条件变量是 c++11 的一个方面,我还在苦苦挣扎。从我收集的内容来看,条件变量与信号量非常相似。

但话又说回来,信号量不需要锁来工作。条件变量可以。而锁又需要一个互斥锁。因此,为了使用信号量相当简单的功能,我们现在不仅需要管理条件变量。但也是互斥体和锁。

那么为什么条件变量需要这个?加上这个要求又提供了哪些附加功能?

【问题讨论】:

  • 互斥锁是锁。线程类锁只是对互斥体的 RAII 包装器,因此它不是托管的,而是在本地使用的。
  • 切向相关:您可以很容易地根据互斥锁和条件变量实现信号量。条件变量只是一个不同的等待原语;它们使等待一般的、用户代码表达的条件变得更容易。
  • 这不是重复的。这个问题是关于 C++11 的,在这种情况下,为 pthreads 条件变量给出的答案不适用。另请参阅 Mike Vine 答案的底部。

标签: c++ multithreading c++11 concurrency flags


【解决方案1】:

条件变量通常用于表示状态变化。通常需要一个互斥体来进行这种更改,然后是原子信号。

信号量封装了一些状态(标志或计数器)以及信号机制。条件变量更原始,只提供信号。

【讨论】:

  • 至少在 C++ 中,不需要用锁来保护信号。事实上,根据实现如何处理等待线程的调度,在锁内执行信号可能会损害性能。虽然在某些条件下程序逻辑可能依赖于状态变化和信号以原子方式发生的事实,但在使用条件变量时通常并非如此。
  • 不是反过来吗?条件变量是互斥体上的信号量。指示互斥量是否再次可用?使信号量更原始。
  • @laurisvr:不,信号量结合了原子标志/计数器和信号,所以它不是原始的。条件变量只是一个信号,您通常将其与您想要发出信号的状态发生变化的其他事物结合使用。
  • 好吧,让我换个说法:)。条件变量需要一些额外的元素(锁和它各自的互斥锁)。因此,条件变量本身更为基本,因为它依赖于标志的互斥锁。但是条件变量包括互斥量和锁。比传统的互斥锁更大,并且产生更多的开销。对吗?
  • @laurisvr:我不明白你的意思;当然,互斥锁加上其他东西比互斥锁要大。或者你的意思是比信号量大?这取决于信号量、互斥量和条件变量是如何实现的。
【解决方案2】:

一般来说,一旦您发出信号(通过条件变量),您需要运行一些代码来处理该更改,并且该代码必须安全地读取更改的数据。如果您没有与 cv 关联的锁,那么您在 cv 上等待的线程可能会唤醒,然后尝试(并失败)获取与数据关联的锁,因此必须再次让步。使用 CV/Lock 组合,只有当线程可以作为一个单元获取相关锁时,底层系统才能唤醒您的线程,因此效率更高。

CV 本身不太可能有用,因为它没有提供任何数据超过它被发出信号的事实。如果您想象 cv 的使用——例如带有生产者和消费者的线程安全链表,您将拥有表示 {list, cv, lock} 的变量。在这种情况下,您获取锁,改变列表,释放锁,然后发出 cv 信号。在您的消费者线程上,您很可能需要在收到信号后获取锁才能对列表进行操作,因此一旦您从收到信号的 CV 中醒来就获得锁是一件好事。 p>

查看类似 Windows 上的事件 (::CreateEvent),它们是没有隐式锁的 cv,很多时候它们会有一个与之关联的锁,但只是没有内置到实际使用中。

虽然这不是创建 pthreads 中条件变量的原始原因(他们使用锁来保护 C++ 中不再需要的 cv 本身),但带有 cv 的锁的原因和有用性已迁移到此答案中的内容.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-02-15
    • 2012-05-25
    • 2011-09-06
    • 2018-02-15
    • 2015-10-31
    • 2012-02-23
    相关资源
    最近更新 更多