C++中的互斥量必须与某个对象或变量绑定吗?

lim*_*imp 7 c++ multithreading mutex

我对线程有点新,我试图理解它在C++ 11中是如何工作的.我班上的教授给了我们这个示例代码来演示互斥锁的用法:

#include <list> 
#include <mutex> 
#include <algorithm>

std::list<int> some_list; // A data structure accessed by multiple threads
std::mutex some_mutex; // This lock will prevent concurrent access to the shared data structure

void
add_to_list(int new_value) {
    std::lock_guard<std::mutex> guard(some_mutex); // Since I am going to access the shared data struct, acquire the lock
    some_list.push_back(new_value); // Now it is safe to use some_list. RAII automatically releases lock at end of function }
}

bool
list_contains(int value_to_find) {
    std::lock_guard<std::mutex> guard(some_mutex); // Must get lock every time I access some_list return
    std::find (some_list.begin(),some_list.end(),value_to_find) != some_list.end();
}
Run Code Online (Sandbox Code Playgroud)

我认为代码有些不言自明,但我有一些具体的问题.

  1. 是否没有必要将互斥锁与列表特别关联?
  2. 如果没有,这是否意味着每次使用互斥锁时,所有线程都会停止,直到互斥锁被破坏为止?或者它只是线程的子集; 也许某些线程池中的线程或相互关联?
  3. 无论哪种情况,只是暂停尝试访问数据结构的线程不是更好吗?因为否则,我们不担心数据竞争等.
  4. 最后,互斥锁和锁之间有什么区别?互斥锁只是一个RAII锁吗?或者RAII是通过警卫发生的吗?

Die*_*Epp 5

  1. 互斥锁与列表相关联,但此关联完全是手动的 - 编译器和运行时库不知道这两者是关联的.该关联完全存在于您的文档和头脑中,您有责任确保访问列表的任何线程首先锁定/获取互斥锁.

  2. 每当使用互斥锁时,锁定/获取互斥锁的线程将停止(该术语实际上是阻塞),直到没有其他线程拥有该互斥锁.不使用互斥锁的线程不受影响.

  3. 您有责任确保只有访问列表的线程锁定/获取互斥锁,并且您还负责确保访问列表的所有线程锁定/获取互斥锁.同样,只有那些线程可以阻止等待互斥锁.

  4. 同一个对象有许多不同的名称:"互斥","锁定"或"临界区".守卫使用RAII来锁定/获取互斥锁.


Guy*_*ton 2

是否不需要专门将互斥体与列表关联起来?

不,您需要手动执行此操作。

如果不是,这是否意味着任何时候使用互斥锁时,所有线程都会停止,直到互斥锁被销毁为止?或者它只是线程的一个子集;也许某个线程池中的线程或以其他方式相互关联?

互斥=互斥。如果两个线程尝试锁定互斥体,其中一个线程将阻塞,直到互斥体被释放。如果您尝试锁定互斥体,而另一个线程拥有锁,它将阻塞,直到它被释放。

无论哪种情况,仅停止尝试访问数据结构的线程不是更好吗?因为否则,我们并不担心数据竞争等问题。

是的。当存在并发访问问题时,您应该只锁定保护数据结构的互斥体。例如修改数据结构时。这就是为什么您的函数仅在 的持续时间内add_to_list锁定互斥锁 ( ) 。some_mutexsome_list.push_back()

最后,互斥锁和锁有什么区别?互斥锁只是 RAII 锁吗?

C++ lock_guard 是互斥锁的 RAII 包装器。当对象被创建时,互斥体被锁定,当对象被销毁(超出范围)时,互斥体被解锁。