使用条件变量优于互斥锁的优点

Abh*_*bhi 25 variables multithreading mutex pthreads conditional-statements

我想知道在pthreads中使用条件变量而不是互斥锁的性能优势是什么.

我发现:"没有条件变量,程序员需要让线程连续轮询(可能在一个关键部分),检查是否满足条件.这可能非常耗费资源,因为线程会持续忙于此条件变量是一种在没有轮询的情况下实现相同目标的方法." (https://computing.llnl.gov/tutorials/pthreads)

但似乎互斥锁调用也是阻塞的(与自旋锁不同).因此,如果线程(T1)无法获得锁定,因为某些其他线程(T2)具有锁定,则操作系统将T1置于休眠状态,并且仅在T2释放锁定并且OS为T1提供锁定时才唤醒.线程T1没有真正轮询以获得锁定.从该描述中,似乎使用条件变量没有性能优势.在任何一种情况下,都不涉及民意调查.操作系统无论如何都提供了条件变量范例可以提供的好处.

你能解释一下究竟发生了什么吗?

Mic*_*urr 50

条件变量允许在该线程感兴趣的事件发生时发出信号.

互联网本身不会这样做.

如果您只需要互斥,则条件变量不会为您做任何事情.但是,如果您需要知道什么时候发生,那么条件变量可以提供帮助.

例如,如果您有一个要处理的项目队列,那么您将拥有一个互斥锁,以确保在由各种生产者和消费者线程访问时队列的内部是一致的.但是,当队列为空时,消费者线程如何知道什么时候它在哪里工作呢?如果没有条件变量之类的东西,则需要轮询队列,在每次轮询时获取和释放互斥锁(否则生产者线程永远不会在队列中放置某些内容).

使用条件变量可以让消费者发现当队列为空时,它可以等待条件变量,指示队列已经放入了某些东西.没有轮询 - 该线程在生产者将某些东西放入队列之前什么也不做,然后表示队列有新项目的条件.

  • 对.互斥锁只允许您等到锁定可用; 条件变量允许您等到某个应用程序定义的条件发生更改. (10认同)
  • 我不明白为什么你不能删除条件变量,只是在一些简单的情况下使用互斥锁.获取互斥锁"工作可用"条件.然后让生产者线程获取互斥锁,工作线程尝试获取它.当工作可用时,生产者解锁互斥锁.然后操作系统将使用获取的互斥锁唤醒工作人员,并且工作人员将运行完成然后通过尝试重新获取其自己的互斥锁来休眠(死锁本身).一旦生产者有更多工作,它就可以解锁互斥锁.可能需要注意检查互斥锁是否先被锁定. (6认同)
  • 假设一个非递归的互斥锁(同一个线程不能锁定多次),@ Eloff,你的想法将使所有东西死锁,而不仅仅是消费者线程("本身").生产者线程无法解锁它未锁定的互斥锁,因此它将永远停留在等待消费者解锁互斥锁,因为它试图重新锁定已经锁定的互斥锁,因此它永远不会解锁互斥锁. (2认同)

seh*_*seh 7

你在两个独立但相关的东西中寻找太多的重叠:互斥和条件变量.

互斥锁的常见实现方法是使用标志和队列.该标志指示互斥锁是否由任何人持有(单计数信号量也可以工作),并且队列跟踪哪些线程在等待独占获取互斥锁.

然后将条件变量实现为另一个用螺栓固定到该互斥锁上的队列.排队等待获取互斥锁的线程通常一旦获得它,就可以自愿离开线路前进并进入条件队列.此时,您有两组独立的服务员:

  • 那些等待专门获得互斥的人
  • 那些等待条件变量发出信号的人

当一个持有互斥锁的线程专门发出条件变量信号时,我们现在假设它是一个单一信号(释放不超过一个等待线程)而不是广播(释放所有等待线程),第一个线程在条件变量队列被分流回到互斥队列的前端(通常).一旦当前持有互斥锁的线程 - 通常是发出条件变量的线程 - 放弃互斥锁,互斥锁队列中的下一个线程就可以获取它.行中的下一个线程将是条件变量队列的头部.

有很多复杂的细节可以发挥作用,但这个草图应该让你感受到游戏中的结构和操作.


joh*_*ash 5

如果您正在寻找性能,那么请开始阅读"非阻塞/非锁定"线程同步算法.它们基于原子操作,这种操作gcc足以提供.查找gcc原子操作.我们的测试表明,使用原子操作幅度比使用互斥锁定更快,我们可以使用多个线程增加全局值. 下面是一些示例代码,演示如何在不锁定的情况下同时从多个线程向链接列表添加项目.

对于睡眠和唤醒线程,信号比条件快得多.您pthread_kill用来发送信号,并使sigwait线程休眠.我们也测试了同样的性能优势. 这是一些示例代码.