何时需要一个条件变量,是不是一个互斥量?

leg*_*s2k 47 multithreading synchronization operating-system mutex condition-variable

我确定互斥是不够的,这就是条件变量概念存在的原因; 但它打败了我,当一个条件变量必不可少时,我无法用一个具体的场景来说服自己.

条件变量,互斥锁和锁定问题的接受答案之间的区别是条件变量是a

锁定"信号"机制.当线程需要等待资源变得可用时使用它.线程可以在CV上"等待",然后资源生成器可以"发出信号"变量,在这种情况下,等待CV的线程会得到通知并可以继续执行

我感到困惑的是,一个线程也可以在互斥锁上等待,当它被发出信号时,只是意味着该变量现在可用,为什么我需要一个条件变量?

PS:此外,无论如何,需要一个互斥锁来保护条件变量,当我的视力更加偏向于看不到条件变量的目的时.

slo*_*elj 30

即使您可以按照您描述的方式使用它们,但互斥锁并非设计用作通知/同步机制.它们旨在提供对共享资源的互斥访问.使用互斥锁发出信号是很尴尬的,我想看起来像这样(Thread2由Thread2发出信号):

线程1:

while(1) {
    lock(mutex); // Blocks waiting for notification from Thread2
    ... // do work after notification is received
    unlock(mutex); // Tells Thread2 we are done
}
Run Code Online (Sandbox Code Playgroud)

线程2:

while(1) {
    ... // do the work that precedes notification
    unlock(mutex); // unblocks Thread1
    lock(mutex); // lock the mutex so Thread1 will block again
}
Run Code Online (Sandbox Code Playgroud)

这有几个问题:

  1. 在Thread1完成"通知后工作"之前,Thread2无法继续"执行通知之前的工作".使用这种设计,Thread2甚至不是必需的,也就是说,为什么不将"先前的工作"和"通知后的工作"移动到同一个线程中,因为只有一个可以在给定的时间运行!
  2. 如果Thread2无法抢占Thread1,则Thread1将在重复while(1)循环时立即重新锁定互斥锁,并且即使没有通知,Thread1也会执行"通知后工作".这意味着你必须以某种方式保证Thread2会在Thread1之前锁定互斥锁.你是怎样做的?可能通过睡眠或某些其他特定于操作系统的方式强制执行调度事件,但即使这不能保证根据时间,操作系统和调度算法工作.

这两个问题并不轻微,事实上,它们都是主要的设计缺陷和潜在的错误.这两个问题的根源是要求在同一个线程中锁定和解锁互斥锁.那么你如何避免上述问题呢?使用条件变量!

顺便说一句,如果您的同步需求非常简单,您可以使用一个简单的旧信号量,避免条件变量的额外复杂性.

  • 感谢您的精心回复.此外,我发现通过尝试使用互斥量来代替条件,并且看到如果T1在T2之前抓住锁定,等待T2信号的整个点都消失了,T1将以错误的资源结束.因此,条件变量用于表示"嘿,我已经完成",而互斥量则用于"你先去或我先去?" - CV = T1取决于T2,Mutex = T1与T2竞争 (7认同)
  • 确切地说,"不良资源"是我的第2号,我将其描述为"T1即使没有通知也会运行".你把它描述为"糟糕的资源"甚至更好. (2认同)

Dag*_*ang 7

Mutex用于独占访问共享资源,而条件变量用于等待条件为真.人们可能认为他们可以在没有内核支持的情况下实现条件变量.人们可能提出的一个常见解决方案是"flag + mutex"就像:

lock(mutex)

while (!flag) {
    sleep(100);
}

unlock(mutex)

do_something_on_flag_set();
Run Code Online (Sandbox Code Playgroud)

但它永远不会工作,因为你在等待期间永远不会释放互斥锁,没有其他人可以以线程安全的方式设置标志.这就是为什么我们需要条件变量,当你等待一个条件变量时,你的线程不会保持相关的互斥锁,直到它被发出信号.


Bas*_*tch 5

您需要条件变量,与互斥体一起使用(每个 cond.var. 属于一个互斥体),以发出从一个线程到另一个线程的状态(条件)变化信号。这个想法是线程可以等待直到某些条件成立。这些条件是特定于程序的(即“队列为空”、“矩阵很大”、“某些资源几乎耗尽”、“某些计算步骤已完成”等)。互斥体可能有几个相关的条件变量。您需要条件变量,因为此类条件可能并不总是简单地表达为“互斥体被锁定”(因此您需要将条件的更改广播到其他线程)。

阅读一些好的 posix 线程教程,例如本教程那个那个教程。更好的是,阅读一本好的 pthread 书籍。看到这个问题

另请阅读高级 Unix 编程高级 Linux 编程

PS 并行和线程是很难掌握的概念。花时间阅读、尝试、再阅读。

  • 我认为问题实际上是“为什么我不能只是等待互斥体解锁而不是使用条件变量” (2认同)

MBI*_*MBI 5

我也在考虑这个问题,最重要的信息,我到处都缺少的是,互斥量只能在一个线程中拥有(和更改).因此,如果您有一个生产者和更多的消费者,生产者将不得不等待互斥产生.与cond.他可以随时生产的变量.