条件变量,互斥锁和锁之间的差异

时间:2009-06-28 18:07:12

标签: c++ multithreading c++11 mutex condition-variable

例如c++0x interfaces

我很难搞清楚何时使用这些东西(cv,互斥锁和锁)。 任何人都可以解释或指向资源吗?

提前致谢。

3 个答案:

答案 0 :(得分:66)

在您引用的页面上,“mutex”是实际的低级同步原语。您可以使用互斥锁然后释放它,并且只有一个线程可以在任何时候使用它(因此它是同步原语)。递归互斥锁是可以由相同的线程多次执行的,然后需要在同一个线程中释放多次,然后其他人才可以使用它。

这里的“锁”只是一个C ++包装类,它在构造函数中使用互斥锁并在析构函数中释放它。它对于为C ++范围建立同步很有用。

条件变量是更高级/高级形式的同步原语,它将锁与“信令”机制相结合。当线程需要等待资源变得可用时使用它。线程可以在CV上“等待”,然后资源生成器可以“发出信号”变量,在这种情况下,等待CV的线程会得到通知并可以继续执行。将互斥锁与CV组合以避免竞争条件,其中线程开始在CV上等待另一个线程想要发信号;那么信号是否被传递或丢失是无法控制的。

答案 1 :(得分:5)

我不太熟悉w / C ++ 0x所以拿这个答案带一点点盐。

re:Mutex vs. locks:从您发布的文档中,看起来mutex是表示操作系统互斥锁的对象,而lock是一个包含互斥锁的对象,以方便RAII pattern

条件变量是一种将阻塞/信令机制(信号+等待)与互斥机制相关联的便捷机制,但它们在操作系统中保持解耦,以便您作为系统程序员可以选择condvar和互斥锁之间的关联。 (对于处理多组并发访问的对象很有用)Rob Krten在good explanations on condvars的一个在线章节中有一些book on QNX

就一般参考文献而言:This book(尚未出来)看起来很有趣。

答案 2 :(得分:0)

这个问题已经回答。我仅添加此内容可能有助于确定何时使用这些同步原语。

简单来说,互斥锁用于确保在多个线程的关键部分相互访问共享资源。运气是一个通用术语,但是二进制互斥锁可以用作锁。在现代C ++中,我们使用lock_guard和类似的对象来利用RAII来简化并确保互斥量的使用安全。条件变量是另一个原语,通常与互斥体结合使用以使事物称为monitor

  

我很难弄清楚何时使用这些东西中的哪些   (简历,互斥锁和锁定)。任何人都可以解释或指向   资源?

使用互斥锁来确保互斥访问某些内容。它是解决大量并发问题的默认解决方案。如果您在C ++中有一个范围要使用互斥量进行保护,请使用lock_guard。互斥锁由lock_guard处理。您只需在范围内创建一个lock_guard并使用互斥锁对其进行初始化,然后C ++会为您完成其余工作。当从堆栈中删除范围时,由于任何原因(包括引发异常或从函数返回),都将释放互斥量。这是RAII背后的想法,而lock_guard是另一个资源处理程序。

有一些并发问题,仅使用互斥锁或简单的解决方案不易解决,这可能导致复杂性或效率低下。例如,produced-consumer problem是其中之一。如果我们想实现一个消费者线程来读取与生产者共享的缓冲区中的项,则应该使用互斥锁来保护缓冲区,但是在不使用条件变量的情况下,我们应该锁定互斥锁,检查缓冲区并读取不为空的项,将其解锁并等待一段时间,然后再次锁定并继续。如果缓冲区经常为空(忙于等待),那会浪费时间,而且还会有很多锁定和解锁以及睡眠。

我们需要的生产者-消费者问题解决方案必须更简单,更有效。监视器(互斥锁+条件变量)在这里为我们提供了帮助。我们仍然需要一个互斥体来保证互斥访问,但是条件变量可以让我们休眠并等待特定条件。这里的条件是生产者将一个项目添加到缓冲区。生产者线程通知消费者线程缓冲区中有物品,消费者醒来并获得物品。简单来说,生产者将锁定互斥锁,将某些内容放入缓冲区中,然后通知消费者。使用者锁定互斥锁,在等待条件时休眠,在缓冲区中有内容时唤醒,并从缓冲区中获取项目。这是一个更简单,更有效的解决方案。

下次遇到并发问题时,请考虑以下方式:如果您需要互斥访问某些内容,请使用互斥锁。如果您想更安全,更简单,请使用lock_guard。如果问题有线索等待另一个线程中必须发生的条件,则您可能需要条件变量。

作为一般的经验法则,首先,分析问题并尝试找到与您的问题类似的著名并发问题(例如,请参见this page中的经典同步问题部分)。阅读有关为知名解决方案提出最佳解决方案的建议。您可能需要一些自定义。