C++ 条件变量、互斥锁和锁的区别
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1055398/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Differences between Conditional variables, Mutexes and Locks
提问by Ronny Brendel
For example the c++0x interfaces
例如c++0x 接口
I am having a hard time figuring out when to use which of these things (cv, mutex and lock). Can anyone please explain or point to a resource?
我很难弄清楚什么时候使用这些东西(cv、互斥锁和锁)。任何人都可以解释或指向资源吗?
Thanks in advance.
提前致谢。
回答by Antti Huima
On the page you refer to, "mutex" is the actual low-level synchronizing primitive. You can take a mutex and then release it, and only one thread can take it at any single time (hence it is a synchronizing primitive). A recursive mutex is one which can be taken by the samethread multiple times, and then it needs to be released as many times by the same thread before others can take it.
在您引用的页面上,“互斥锁”是实际的低级同步原语。您可以获取互斥锁然后释放它,并且在任何时候只有一个线程可以获取它(因此它是一个同步原语)。递归互斥量是一个可以被同一个线程多次占用的互斥锁,然后它需要被同一个线程释放多次,其他人才能获取它。
A "lock" here is just a C++ wrapper class that takes a mutex in its constructor and releases it at the destructor. It is useful for establishing synchronizing for C++ scopes.
这里的“锁”只是一个 C++ 包装类,它在其构造函数中接受一个互斥锁并在析构函数中释放它。它对于建立 C++ 作用域的同步很有用。
A condition variable is a more advanced / high-level form of synchronizing primitive which combines a lock with a "signaling" mechanism. It is used when threads need to wait for a resource to become available. A thread can "wait" on a CV and then the resource producer can "signal" the variable, in which case the threads who wait for the CV get notified and can continue execution. A mutex is combined with CV to avoid the race condition where a thread starts to wait on a CV at the same time another thread wants to signal it; then it is not controllable whether the signal is delivered or gets lost.
条件变量是一种更高级/高级形式的同步原语,它将锁与“信号”机制相结合。当线程需要等待资源可用时使用它。线程可以在 CV 上“等待”,然后资源生产者可以“发出信号”变量,在这种情况下,等待 CV 的线程会得到通知并可以继续执行。互斥体与 CV 相结合,以避免出现竞争条件,即一个线程开始等待 CV,同时另一个线程想要向它发出信号;那么信号是传递还是丢失是不可控的。
回答by Jason S
I'm not too familiar w/ C++0x so take this answer w/ a grain of salt.
我对 C++0x 不太熟悉,所以请保留这个答案。
re: Mutex vs. locks: From the documentation you posted, it looks like a mutex
is an object representing an OS mutex, whereas a lock
is an object that holds a mutex to facilitate the RAII pattern.
回复:互斥锁与锁:从您发布的文档中,看起来 amutex
是一个表示操作系统互斥锁lock
的对象,而 a是一个持有互斥锁以促进RAII 模式的对象。
Condition variables are a handy mechanism to associate a blocking/signaling mechanism (signal+wait) with a mutual exclusion mechanism, yet keep them decoupled in the OS so that you as system programmer can choose the association between condvar and mutex. (useful for dealing with multiple sets of concurrently-accessed objects) Rob Krten has some good explanations on condvarsin one of the online chapters of his book on QNX.
条件变量是一种方便的机制,可以将阻塞/信号机制(信号+等待)与互斥机制相关联,但在操作系统中保持它们解耦,以便您作为系统程序员可以选择 condvar 和互斥体之间的关联。(对于处理多组并发访问的对象很有用)Rob Krten在他关于 QNX 的书的在线章节之一中对condvars 有一些很好的解释。
As far as general references: This book(not out yet) looks interesting.
至于一般参考:这本书(尚未出版)看起来很有趣。
回答by Aliakbar Abbasi
This question has been answered. I just add this that may help to decide WHEN to use these synchronization primitives.
这个问题已经回答了。我只是添加这可能有助于决定何时使用这些同步原语。
Simply, the mutex is used to guarantee mutual access to a shared resource in the critical section of multiple threads. The luck is a general term but a binary mutex can be used as a lock. In modern C++ we use lock_guard and similar objects to utilize RAII to simplify and make safe the mutex usage. The conditional variable is another primitive that often combined with a mutex to make something know as a monitor.
简单的说,互斥锁是用来保证多线程临界区共享资源的相互访问。运气是一个通用术语,但二进制互斥锁可以用作锁。在现代 C++ 中,我们使用 lock_guard 和类似的对象来利用 RAII 来简化和确保互斥锁的使用。条件变量是另一种原语,通常与互斥锁相结合,将某些东西称为监视器。
I am having a hard time figuring out when to use which of these things (cv, mutex and lock). Can anyone please explain or point to a resource?
我很难弄清楚什么时候使用这些东西(cv、互斥锁和锁)。任何人都可以解释或指向资源吗?
Use a mutex to guarantee mutual exclusive access to something. It's the default solution for a broad range of concurrency problems. Use lock_guard if you have a scope in C++ that you want to guard it with a mutex. The mutex is handled by the lock_guard. You just create a lock_guard in the scope and initialize it with a mutex and then C++ does the rest for you. The mutex is released when the scope is removed from the stack, for any reason including throwing an exception or returning from a function. It's the idea behind RAIIand the lock_guard is another resource handler.
使用互斥锁来保证对某些东西的互斥访问。它是各种并发问题的默认解决方案。如果您在 C++ 中有一个范围并且想要使用互斥锁保护它,请使用 lock_guard。互斥锁由 lock_guard 处理。您只需在作用域中创建一个 lock_guard 并使用互斥锁对其进行初始化,然后 C++ 为您完成剩下的工作。当作用域从堆栈中移除时,互斥量被释放,包括抛出异常或从函数返回在内的任何原因。这是RAII背后的想法,而 lock_guard 是另一个资源处理程序。
There are some concurrency issues that are not easily solvable by only using a mutex or a simple solution can lead to complexity or inefficiency. For example, the produced-consumer problemis one of them. If we want to implement a consumer thread reading items from a buffer shared with a producer, we should protect the buffer with a mutex but, without using a conditional variable we should lock the mutex, check the buffer and read an item if it's not empty, unlock it and wait for some time period, lock it again and go on. It's a waste of time if the buffer is often empty (busy waiting) and also there will be lots of locking and unlocking and sleeps.
有一些并发问题仅使用互斥锁是不容易解决的,或者一个简单的解决方案会导致复杂性或低效率。例如,生产者-消费者问题就是其中之一。如果我们想实现一个消费者线程从与生产者共享的缓冲区中读取项目,我们应该用互斥锁保护缓冲区,但是,在不使用条件变量的情况下,我们应该锁定互斥锁,检查缓冲区并读取一个项目,如果它不为空,解锁并等待一段时间,再次锁定并继续。如果缓冲区经常是空的(忙等待)并且会有大量的锁定和解锁和睡眠,那是在浪费时间。
The solution we need for the producer-consumer problem must be simpler and more efficient. A monitor (a mutex + a conditional variable) helps us here. We still need a mutex to guarantee mutual exclusive access but a conditional variable lets us sleep and wait for a certain condition. The condition here is the producer adding an item to the buffer. The producer thread notifies the consumer thread that there is and item in the buffer and the consumer wakes up and gets the item. Simply, the producer locks the mutex, puts something in the buffer, notifies the consumer. The consumer locks the mutex, sleeps while waiting for a condition, wake s up when there is something in the buffer and gets the item from the buffer. It's a simpler and more efficient solution.
我们需要的生产者-消费者问题的解决方案必须更简单、更高效。一个监视器(一个互斥体 + 一个条件变量)在这里帮助我们。我们仍然需要一个互斥体来保证互斥访问,但条件变量让我们休眠并等待某个条件。这里的条件是生产者向缓冲区添加一个项目。生产者线程通知消费者线程缓冲区中有项目,消费者唤醒并获取项目。简单地说,生产者锁定互斥锁,在缓冲区中放入一些东西,通知消费者。消费者锁定互斥锁,在等待条件时休眠,当缓冲区中有东西时唤醒并从缓冲区中获取项目。这是一个更简单、更有效的解决方案。
The next time you face a concurrency problem think this way: If you need mutual exclusive access to something, use a mutex. Use lock_guard if you want to be safer and simpler. If the problem has a clue of waiting for a condition that must happen in another thread, you MIGHT need a conditional variable.
下次遇到并发问题时,请这样想:如果您需要互斥访问某些内容,请使用互斥锁。如果您想更安全、更简单,请使用 lock_guard。如果问题有等待必须在另一个线程中发生的条件的线索,则您可能需要一个条件变量。
As a general rule of thumb, first, analyze your problem and try to find a famous concurrency problem similar to yours (for example, see classic problems of synchronization section in this page). Read about the solutions proposed for the well-known solution to peak the best one. You may need some customization.
作为一般经验法则,首先,分析您的问题并尝试找到与您的问题相似的著名并发问题(例如,请参阅本页同步部分的经典问题)。阅读有关为达到最佳解决方案而提出的著名解决方案的解决方案。您可能需要一些自定义。