multithreading - 条件变量与信号量

标签 multithreading operating-system synchronization semaphore mutual-exclusion

什么时候应该使用信号量,什么时候应该使用条件变量(CondVar)?

最佳答案

锁用于互斥。当你想确保一段代码是原子的时,在它周围放一个锁。理论上,您可以使用二进制信号量来执行此操作,但这是一种特殊情况。

信号量和条件变量建立在锁提供的互斥之上,用于提供对共享资源的同步访问。它们可用于类似目的。

条件变量通常用于避免在等待资源可用时忙等待(检查条件时重复循环)。例如,如果您有一个线程(或多个线程)在队列为空之前无法继续前进,那么忙等待方法就是执行以下操作:

//pseudocode
while(!queue.empty())
{
   sleep(1);
}

这样做的问题是,让这个线程反复检查条件,是在浪费处理器时间。为什么不用一个同步变量来通知线程资源可用呢?
//pseudocode
syncVar.lock.acquire();

while(!queue.empty())
{
   syncVar.wait();
}

//do stuff with queue

syncVar.lock.release();

据推测,您将在其他地方有一个线程将事物从队列中拉出。当队列为空时,可以调用syncVar.signal()唤醒一个在 syncVar.wait() 上睡着的随机线程(或者通常还有一个 signalAll()broadcast() 方法来唤醒所有正在等待的线程)。

当我有一个或多个线程等待单个特定条件(例如队列为空)时,我通常使用这样的同步变量。

信号量可以类似地使用,但我认为当您拥有一个共享资源时,它们会更好地使用,该资源可以根据一些整数数量的可用事物来使用和不可用。信号量适用于生产者/消费者情况,即生产者分配资源而消费者消费它们。

想想你是否有汽水自动售货机。只有一台汽水机,而且是共享资源。您有一个线程是负责保持机器库存的供应商(生产者)和 N 个线程是希望从机器中取出苏打水的买家(消费者)。机器中苏打水的数量是驱动我们信号量的整数值。

每个来到汽水机的买家(消费者)线程都会调用信号量 down()喝苏打水的方法。这将从机器中获取苏打水并将可用苏打水的计数减 1。如果有苏打水可用,代码将继续运行超过 down()。声明没有问题。如果没有可用的苏打水,线程将在此处休眠,等待在苏打水再次可用时收到通知(当机器中有更多苏打水时)。

供应商(生产者)线程本质上将等待汽水机为空。当最后一杯汽水从机器中取出时,供应商会收到通知(一个或多个消费者可能正在等待取出汽水)。供应商将使用信号量重新进货汽水机 up()方法,苏打水的可用数量每次都会增加,因此等待的消费者线程将收到更多苏打水可用的通知。
wait()signal()同步变量的方法往往隐藏在 down() 中和 up()信号量的操作。

当然,这两种选择之间存在重叠。在许多情况下,信号量或条件变量(或条件变量集)都可以满足您的目的。信号量和条件变量都与一个锁对象相关联,它们用来维护互斥,但是它们在锁之上提供了额外的功能来同步线程执行。主要由您决定哪一种最适合您的情况。

这不一定是最具技术性的描述,但这就是我脑海中的意义。

关于multithreading - 条件变量与信号量,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3513045/

相关文章:

c++ - 多线程和多进程应用程序的锁定机制有什么区别?

c# - WSACancelBlockingCall 异常

C++访问另一个类的数据成员

memory-management - 如果我们有无限内存,那么我们还需要分页吗?

php - 如何将 drupal 事件日历与 Outlook 日历同步

c# - 线程退出时如何处理 ThreadLocal 值?

network-programming - 如何从 golang 程序中设置 ulimit -n?

c - 如何编译这个hello world操作系统?

mysql - 检查存在并与数百万行同步数据

linux - 两个进程写入一个文件,防止混合输出