c++ - scoped_lock 可以在读取模式下锁定 shared_mutex 吗?
问题描述
C++17 引入了std::shared_mutex
和std::scoped_lock
. scoped_lock
我现在的问题是,当它作为参数传递时,它似乎总是将共享互斥锁锁定在独占(写入器)模式,而不是在共享(读取器)模式下。在我的应用程序中,我需要dst
使用来自 object 的数据更新 object src
。我想锁定src
共享和dst
独占。src
不幸的是,如果同时使用和dst
切换调用另一个更新方法,这有可能导致死锁。所以我想使用std::scoped_lock
.
我可以scoped_lock
同时锁定src
和dst
独占模式,但是这种不必要的严格锁定会在其他地方产生性能回退。但是,似乎可以将src
's包装shared_mutex
成 astd::shared_lock
并将其与 : 一起使用scoped_lock
:当scoped_lock
在其锁定操作期间调用try_lock()
时shared_lock
,后者实际上会调用try_shared_lock()
' src
s shared_mutex
,这就是我所需要的。
所以我的代码看起来很简单:
struct data {
mutable std::shared_mutex mutex;
// actual data follows
};
void update(const data& src, data& dst)
{
std::shared_lock slock(src.mutex, std::defer_lock);
std::scoped_lock lockall(slock, dst.mutex);
// now can safely update dst with src???
}
在另一个(避免死锁)锁卫中使用这样的(共享)锁卫是否安全?
解决方案
正如阅读过 C++ 标准库的实现代码的各种评论员所指出的那样:是的,使用std::shared_mutex
包裹在 a中的 astd::shared_lock()
作为参数之一std::scoped_lock()
是安全的。
基本上,astd::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
根据cppreference是一个包装器std::lock
,增加了在其析构函数中调用unlock()
每个 Lockable 对象的功能。这里不需要添加的功能,因为std::shared_lock lk1
它std::unique_lock lk2
也可以用作锁守卫,当它们超出范围时解锁它们的互斥锁。
编辑:各种澄清
推荐阅读
- git - 来自 Visual Studio Code 和 Visual Studio(但不是 Git Bash)的“权限被拒绝”错误
- vba - 将每个页面保存为它自己的文档,标题为来自数据源的值
- python - 尝试在 Pycharm 的 python 控制台中运行此函数,但无论我将返回函数放在哪里,我都会收到错误消息
- python - 在 Dataflow Python flex 模板中包含另一个文件 ImportError
- postgresql-9.5 - 没有与 ON CONFLICT 规范匹配的唯一或排除约束
- python - 创建第二个索引列以获取 2 级 MultiIndex
- sql - BigQuery 中按 2 列分区
- javascript - 如何通过 HTML DOM 向元素添加 oninput 属性?
- java - Web 服务器中的速率限制
- google-apps-script - 所需权限:https://www.googleapis.com/auth/spreadsheets