C ++ 17引入了std::shared_mutex
和std::scoped_lock
。现在我的问题是,scoped_lock
似乎将共享互斥锁始终作为互斥(写入器)模式(当作为参数传递时,而不是共享(读取器)模式)锁定。在我的应用中,我需要使用来自对象dst
的数据更新对象src
。我想锁定共享的src
和独占的dst
。不幸的是,如果同时切换了src
和dst
的另一种更新方法的调用,则有可能导致死锁。因此,我想使用std::scoped_lock
的奇特的避免死锁机制。
我可以在独占模式下使用scoped_lock
来锁定src
和dst
,但是不必要的严格锁定会在其他地方降低性能。但是,似乎可以将src
的{{1}}包裹到shared_mutex
中,并与std::shared_lock
一起使用:在scoped_lock
上锁定动作调用scoped_lock
,稍后实际上会在try_lock()
的{{1}}上调用shared_lock
,这就是我需要的。
所以我的代码看起来像这样简单:
try_shared_lock()
在另一个(避免死锁)锁保护装置中使用这样的(共享)锁保护装置安全吗?
答案 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
对象并将其全部锁定(或异常中止,在这种情况下它们将全部被解锁)。
Lockable
是std::scoped_lock
的包装,具有在其析构函数中的每个Lockable对象上调用std::lock
的功能。这里不需要该附加功能,因为unlock()
和std::shared_lock lk1
还可作为锁定防护,当它们超出范围时解锁互斥体。
编辑:各种说明
答案 1 :(得分:0)
Mutex :为共享资源添加线程安全性
锁定:将RAII(可能还有其他功能)添加到互斥锁中
不同的锁让您以不同的方式锁定互斥锁:
scoped_lock
是裸露的骨骼专用锁,在构造时会被锁定,在破坏时会被解锁。 unique_lock
和shared_lock
分别是互斥锁和共享锁,它们也分别使用其默认构造函数和析构函数进行锁定和解锁。但是,它们还提供了额外的功能。例如,您可以try to luck them,也可以在销毁它们之前将其解锁。
因此,典型的用例是使用shared_lock
进行共享访问(当多个线程读取同一资源时),并使用unique_lock
或scoped_lock
进行互斥访问(取决于您是否需要unique_lock
的其他功能。