Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 何时需要条件变量,isn';互斥还不够吗?_Multithreading_Operating System_Synchronization_Mutex_Condition Variable - Fatal编程技术网

Multithreading 何时需要条件变量,isn';互斥还不够吗?

Multithreading 何时需要条件变量,isn';互斥还不够吗?,multithreading,operating-system,synchronization,mutex,condition-variable,Multithreading,Operating System,Synchronization,Mutex,Condition Variable,我确信互斥是不够的,这就是条件变量概念存在的原因;但这让我感到困惑,我无法用一个具体的场景说服自己,当一个条件变量是必不可少的 问题的公认答案是,条件变量是 用“信号”机制锁定。当线程需要时使用它 等待资源变为可用。线程可以在CV上“等待” 然后,资源生产者可以“发送”变量,其中 案例等待CV的线程得到通知并可以继续 执行 我感到困惑的是,线程也可以在互斥体上等待,当它收到信号时,仅仅意味着变量现在可用,为什么我需要一个条件变量 另外,当我的视线更倾向于看不到条件变量的用途时,无论如何都需要一个

我确信互斥是不够的,这就是条件变量概念存在的原因;但这让我感到困惑,我无法用一个具体的场景说服自己,当一个条件变量是必不可少的

问题的公认答案是,条件变量是

用“信号”机制锁定。当线程需要时使用它 等待资源变为可用。线程可以在CV上“等待” 然后,资源生产者可以“发送”变量,其中 案例等待CV的线程得到通知并可以继续 执行

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


另外,当我的视线更倾向于看不到条件变量的用途时,无论如何都需要一个互斥来保护条件变量。

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

阅读一些好的posix线程教程,例如or或one。更好的是,读一本好的pthread书籍。看

也读和


p.S.平行度和线程是很难掌握的概念。花点时间阅读、实验并再次阅读。

即使您可以按照您描述的方式使用它们,互斥锁也不是为用作通知/同步机制而设计的。它们旨在提供对共享资源的互斥访问。使用互斥体来表示条件是很尴尬的,我想应该是这样的(其中Thread1由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
}
lock(mutex0);
while(1) {
    lock(mutex0); // Blocks waiting for notification from Thread2
    ... // do work after notification is received
    unlock(mutex1); // Tells Thread2 we are done
}
线程2:

while(1) {
    ... // do the work that precedes notification
    unlock(mutex); // unblocks Thread1
    lock(mutex); // lock the mutex so Thread1 will block again
}
while(1) {
    lock(mutex1); // lock the mutex so Thread1 will block again
    ... // do the work that precedes notification
    unlock(mutex0); // unblocks Thread1
}
这有几个问题:

  • 在Thread1完成“通知后工作”之前,Thread2无法继续“执行通知前的工作”。在这种设计中,甚至不需要Thread2,也就是说,为什么不将“在通知之前的工作”和“在通知之后的工作”移动到同一个线程中,因为在给定时间只有一个线程可以运行
  • 如果Thread2无法抢占Thread1,Thread1将在重复while(1)循环时立即重新锁定互斥锁,Thread1将继续执行“通知后工作”,即使没有通知。这意味着您必须以某种方式保证Thread2将在Thread1锁定互斥锁之前锁定互斥锁。你是怎么做到的?可能通过睡眠或其他特定于操作系统的方式强制调度事件,但即使这样也不能保证根据时间、操作系统和调度算法来工作
  • 这两个问题不是小问题,事实上,它们都是主要的设计缺陷和潜在的bug。这两个问题的根源都是要求在同一线程中锁定和解锁互斥锁。那么如何避免上述问题呢?使用条件变量


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

    互斥用于独占访问共享资源,而条件变量则用于等待条件为真。两者都是不同的内核资源。有些人可能认为他们可以通过互斥实现条件变量,一种常见的模式是“flag+mutex”:


    但它永远不会工作,因为在等待过程中您永远不会释放互斥,其他人无法以线程安全的方式设置该标志。这就是为什么我们需要条件变量,当你在等待一个条件变量时,相关的互斥锁在发出信号之前不会被你的线程保持。

    我也在考虑这个问题,我认为最重要的信息是,互斥锁一次只能由一个线程拥有(或更改)。因此,如果您有一个生产者和多个消费者,生产者将不得不等待互斥来生产。与康德。它可以随时生成变量。

    条件变量和互斥对可以由二进制信号量和互斥对替换。使用条件var+mutex时,使用者线程的操作顺序为:

  • 锁定互斥锁

  • 等待条件变量

  • 过程

  • 解锁互斥锁

  • 生产者线程操作序列为

  • 锁定互斥锁

  • 向条件var发送信号

  • 解锁互斥锁

  • 使用sema+mutex对时对应的使用者线程序列为

  • 等待二进制语义

  • 锁定互斥锁

  • 检查预期条件

  • 如果条件为真,则处理

  • 解锁互斥锁

  • 如果步骤3中的条件检查为假,则返回步骤1

  • 生产者线程的顺序为:

  • 锁定互斥锁

  • 发布二进制语义

  • 解锁互斥锁

  • 正如您可以看到的,在使用条件变量时,步骤3中的无条件处理被步骤3和步骤4中的条件处理(在使用二进制语义时)所取代

    原因是当使用sema+mutex时,在竞争条件下,另一个使用者线程可能会在步骤1和步骤2之间潜入,并处理/取消该条件。在使用条件变量时不会发生这种情况。在使用条件变量时,在步骤2之后,将保证条件为true

    比纳
    while(1) {
        lock(mutex1); // lock the mutex so Thread1 will block again
        ... // do the work that precedes notification
        unlock(mutex0); // unblocks Thread1
    }