![]() |
1
174
锁用于互斥。当您想要确保一段代码是原子代码时,在它周围加上一个锁。理论上可以使用二进制信号量来实现这一点,但这是一种特殊情况。 信号量和条件变量建立在锁提供的互斥之上,用于提供对共享资源的同步访问。它们可以用于类似的用途。 条件变量通常用于在等待资源可用时避免忙碌等待(检查条件时重复循环)。例如,如果有一个线程(或多个线程)在队列为空之前无法继续前进,那么繁忙的等待方法就是执行如下操作:
问题在于,通过让这个线程反复检查条件,您浪费了处理器时间。为什么不使用一个同步变量来通知线程资源可用?
大概,您将在其他地方有一个线程,它将把事情从队列中拉出。当队列为空时,它可以调用
当我有一个或多个线程在一个特定的条件下(例如,队列为空)等待时,我通常使用这样的同步变量。 信号量也可以类似地使用,但我认为,当您有一个基于可用事物的整数可以使用和不可用的共享资源时,最好使用它们。信号量对于生产者/消费者的情况很好,在这种情况下,生产者分配资源,消费者消耗资源。 想想如果你有一台汽水自动售货机。只有一台汽水机,而且是共享资源。您有一个线程是供应商(生产商),负责保持机器的库存,还有n个线程是买家(消费者),他们希望将sodas从机器中取出。机器中的soda数是驱动信号量的整数值。
到汽水机的每个买方(消费者)线程都调用信号量
供应商(生产商)线程基本上是等待苏打机为空。当最后一瓶苏打水从机器中取出时(一个或多个消费者可能正在等待将苏打水取出),供应商会收到通知。售货员会用信号灯给汽水机重新进货。
这个
当然,这两种选择是有重叠的。在许多情况下,信号量或条件变量(或条件变量集)都可以满足您的目的。信号量和条件变量都与它们用来维护互斥的锁对象相关联,但是它们在锁的顶部提供了额外的功能来同步线程执行。这主要是由你自己来决定哪一个对你的处境最有意义。 这不一定是最专业的描述,但这在我的头脑中是有意义的。 |
![]() |
2
32
让我们看看引擎盖下面是什么。 条件变量本质上是一个等待队列 ,它支持阻塞等待和唤醒操作,即可以将线程放入等待队列,并将其状态设置为阻塞,然后从中取出线程,并将其状态设置为就绪。 注意,要使用条件变量,还需要另外两个元素:
然后协议变成,
信号量本质上是一个计数器+一个互斥体+一个等待队列。 它可以像现在这样使用,不需要外部依赖。您可以将它用作互斥量或条件变量。 因此,信号量可以被视为比条件变量更复杂的结构,而条件变量则更轻、更灵活。 |
![]() |
3
14
信号量可以用来实现对变量的独占访问,但是它们是用于同步的。另一方面,互斥体具有严格与互斥相关的语义:只允许锁定资源的进程将其解锁。 不幸的是,您不能实现与互斥体的同步,这就是为什么我们有条件变量。还请注意,通过使用条件变量,可以使用广播解锁在同一瞬间解锁所有等待的线程。这不能用信号量来完成。 |
![]() |
4
5
信号量和条件变量非常相似,主要用于相同的目的。然而,有一些微小的差异可以使人更可取。例如,要实现屏障同步,您将无法使用信号量,但条件变量是理想的。 屏障同步是指您希望所有线程都等待,直到每个线程都到达线程函数的某个部分。这可以通过一个静态变量来实现,该变量最初是每个线程到达该屏障时所减少的线程总数的值。这意味着我们希望每个线程都能休眠到最后一个线程到达为止。信号量正好相反!有了信号量,每个线程都将继续运行,最后一个线程(将信号量值设置为0)将进入睡眠状态。 另一方面,条件变量是理想的。当每个线程到达屏障时,我们检查静态计数器是否为零。如果没有,我们将线程设置为使用条件变量wait函数休眠。当最后一个线程到达屏障时,计数器值将减至零,最后一个线程将调用条件变量信号函数,该函数将唤醒所有其他线程! |
![]() |
5
1
i在监视器同步下归档条件变量。我通常将信号量和监视器看作两种不同的同步样式。这两者在本质上保留了多少状态数据,以及您希望如何对代码建模方面存在差异,但实际上没有任何问题可以由一个而不是另一个来解决。 我倾向于向监视器窗体编码;在大多数语言中,我使用的代码归结为互斥体、条件变量和一些支持状态变量。但是信号灯也可以完成这项工作。 |
![]() |
user3732361 · 读取大文件时如何选择块大小? 6 年前 |
![]() |
Sector · 将参数传递给自己的execv内核实现 6 年前 |
![]() |
Arka Pal · 关闭管道中未使用的端部 6 年前 |
![]() |
Nat · 释放malloc内存时程序停止工作 6 年前 |
![]() |
Mengfan Ma · 作者所说的操作系统中的目录结构是什么意思? 6 年前 |
![]() |
Mengfan Ma · 在何处执行磁盘调度 6 年前 |