关于使用 std::unique_lock 的说明

clarification on using std::unique_lock

所以,我有一个 std::map 对象,它被多个线程同时访问,我决定使用 unique_lock 来确保地图操作安全。

在一个线程的实现中,map 对象被一些函数使用(这些函数通常是来自 map 对象的 add/remove 项),所以我想知道是否定义了 unique_lock父函数的顶部会保证安全吗?或者我需要将它添加到每个函数中?

void Thread1() {
  std::unique_lock<std::mutex> ul(mutex);

  func1();  // map object is getting changed here
  func2();  // map object is getting changed here

}

我看到你在这里的东西不能真正起作用。如果每个线程都试图在操作开始时获取互斥锁,要么你有死锁或顺序线程,其中只有一个线程可以 运行 或者你有多个不同的互斥锁。后者是不正确的,但前者放弃了多线程的一些好处。

如果您对必须锁定的函数使用了更明确的作用域,则可以使用锁而不直接将它们添加到正在使用的函数中。

void Thread1() {
funcA();
{// Explicit scoping
std::unique_lock<std::mutex> ul(mutex);

func1();  // map object is getting changed here
func2();  // map object is getting changed here
}
funcB();

}

我们希望在尽可能短的时间内使用锁。所以你必须判断改变地图对象的函数是否足够小以证明整个时间都锁定。

使用互斥锁的全部意义在于防止线程 B、C、D 等由于线程 A 所做的更改而看到处于不一致状态的共享数据。

你提出了这个:

void Thread1() {
    std::unique_lock<std::mutex> ul(mutex);
    func1();  // map object is getting changed here
    func2();  // map object is getting changed here
}

是否 func1() 将地图(可能还有其他共享变量)置于其他线程不应看到的状态? func2() 是否可以让其他线程再次查看共享数据?如果是这样,那么您的示例可能是您所希望的最好的示例。但是,如果这两个函数调用中的每一个都使共享数据处于 "safe" 状态,那么您可能会考虑让它们分别锁定和解锁 mutex.

如果线程可以设计成它们不经常需要访问共享数据,并且当它们需要 需要访问它,他们会尽快进出(即锁定和解锁)。


另请参阅 readers writer locking (in C++, std::shared_lock),以防您的特定问题得到帮助。