scoped_lock可以在读取模式下锁定shared_mutex吗?

时间:2019-02-12 00:42:03

标签: c++ deadlock scoped-lock

C ++ 17引入了std::shared_mutexstd::scoped_lock。现在我的问题是,scoped_lock似乎将共享互斥锁始终作为互斥(写入器)模式(当作为参数传递时,而不是共享(读取器)模式)锁定。在我的应用中,我需要使用来自对象dst的数据更新对象src。我想锁定共享的src和独占的dst。不幸的是,如果同时切换了srcdst的另一种更新方法的调用,则有可能导致死锁。因此,我想使用std::scoped_lock的奇特的避免死锁机制。

我可以在独占模式下使用scoped_lock来锁定srcdst,但是不必要的严格锁定会在其他地方降低性能。但是,似乎可以将src的{​​{1}}包裹到shared_mutex中,并与std::shared_lock一起使用:在scoped_lock上锁定动作调用scoped_lock,稍后实际上会在try_lock()的{​​{1}}上调用shared_lock,这就是我需要的。

所以我的代码看起来像这样简单:

try_shared_lock()

在另一个(避免死锁)锁保护装置中使用这样的(共享)锁保护装置安全吗?

2 个答案:

答案 0 :(得分:4)

正如阅读了C ++标准库的实现代码的各种注释者所指出的:是的,将包裹在std::shared_mutex中的std::shared_lock()用作{{1 }}是安全的。

基本上,std::scoped_lock()将所有呼叫转移到std::shared_lock到互斥量上的lock()

lock_shared()

另一种可能的解决方案

std::shared_lock::lock -----------> mutex()->lock_shared(). // same for try_lock etc..

std::shared_lock lk1(src.mutex, std::defer_lock); std::unique_lock lk2(dst.mutex, std::defer_lock); std::lock(lk1, lk2); 是一个函数,它接受任意数量的std::lock对象并将其全部锁定(或异常中止,在这种情况下它们将全部被解锁)。

根据{{​​3}}的

Lockablestd::scoped_lock的包装,具有在其析构函数中的每个Lockable对象上调用std::lock的功能。这里不需要该附加功能,因为unlock()std::shared_lock lk1还可作为锁定防护,当它们超出范围时解锁互斥体。

编辑:各种说明

答案 1 :(得分:0)

Mutex :为共享资源添加线程安全性
锁定:将RAII(可能还有其他功能)添加到互斥锁中

不同的锁让您以不同的方式锁定互斥锁:

  • unique_lock:独占访问资源(用于写入)
  • shared_lock:对资源的共享访问(用于同时读取)
  • scoped_lock:与unique_lock相同,但功能较少

scoped_lock是裸露的骨骼专用锁,在构造时会被锁定,在破坏时会被解锁。 unique_lockshared_lock分别是互斥锁和共享锁,它们也分别使用其默认构造函数和析构函数进行锁定和解锁。但是,它们还提供了额外的功能。例如,您可以try to luck them,也可以在销毁它们之前将其解锁。

因此,典型的用例是使用shared_lock进行共享访问(当多个线程读取同一资源时),并使用unique_lockscoped_lock进行互斥访问(取决于您是否需要unique_lock的其他功能。