简体   繁体   English

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

[英]Can scoped_lock lock a shared_mutex in read mode?

C++17 introduced both std::shared_mutex and std::scoped_lock . C ++ 17引入了std::shared_mutexstd::scoped_lock My problem is now, that it seems, that scoped_lock will lock a shared mutex always in exclusive (writer) mode, when it is passed as an argument, and not in shared (reader) mode. 我现在的问题是, scoped_lock似乎总是在独占(写入)模式下锁定共享互斥锁,当它作为参数传递时,而不是共享(读取器)模式。 In my app, I need to update an object dst with data from an object src . 在我的应用程序中,我需要使用来自对象src数据更新对象dst I want to lock src shared and dst exclusive. 我想锁定src shared和dst exclusive。 Unfortunately, this has the potential for deadlock, if a call to another update method with src and dst switched occurs at the same time. 不幸的是,如果同时调用srcdst切换的另一个更新方法,则可能会出现死锁。 So I would like to use the fancy deadlock avoidance mechanisms of std::scoped_lock . 所以我想使用std::scoped_lock的花哨的死锁避免机制。

I could use scoped_lock to lock both src and dst in exclusive mode, but that unnecessarily strict lock has performance backdraws elsewhere. 我可以使用scoped_lock以独占模式锁定srcdst ,但是不必要的严格锁定会在其他地方进行性能回退。 However, it seems, that it is possible to wrap src 's shared_mutex into a std::shared_lock and use that with the scoped_lock : When the scoped_lock during its locking action calls try_lock() on the shared_lock , the later will actually call try_shared_lock() on src 's shared_mutex , and that's what I need. 但是,似乎可以将srcshared_mutex包装到std::shared_lock并将其与scoped_lock一起使用:当scoped_lock在其锁定操作期间调用shared_lock上的try_lock()时,后者将实际调用try_shared_lock()srcshared_mutex ,这就是我需要的东西。

So my code looks as simple as this: 所以我的代码看起来很简单:

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???
}

Is it safe to use a (shared) lock guard like this inside another (deadlock avoidance) lock guard? 在另一个(死锁避免)锁定防护装置中使用这样的(共享)锁定防护装置是否安全?

As pointed out by various commentators, who have read the implementation code of the C++ standard library: Yes, the use of a std::shared_mutex wrapped inside a std::shared_lock() as one of the arguments to std::scoped_lock() is safe. 正如各种评论员所指出的,他们已经阅读了C ++标准库的实现代码:是的,使用std::shared_mutex作为std::scoped_lock()的参数之一包装在std::shared_lock() std::scoped_lock()是安全的。

Basically, a std::shared_lock forwards all calls to lock() to lock_shared() on the mutex. 基本上, std::shared_lock lock_shared() lock()所有调用转发到互斥lock_shared()

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

Another possible solution 另一种可能的解决

std::shared_lock lk1(src.mutex, std::defer_lock);
std::unique_lock lk2(dst.mutex, std::defer_lock);
std::lock(lk1, lk2);

std::lock is a function that accepts any number of Lockable objects and locks all of them (or aborts with an exception, in which case they will all be unlocked). std::lock是一个函数,它接受任意数量的Lockable对象并锁定所有这些对象(或者中止异常,在这种情况下它们都将被解锁)。

std::scoped_lock according to cppreference is a wrapper for std::lock , with the added functionaliy of calling unlock() on each Lockable object in its destructor. 根据cppreference的 std::scoped_lockstd::lock的包装器,添加了在析构函数中对每个Lockable对象调用unlock()功能。 That added functionality is not required here, as std::shared_lock lk1 and std::unique_lock lk2 also work as lock guards, that unlock their mutexes, when they go out of scope. 这里不需要添加功能,因为std::shared_lock lk1std::unique_lock lk2也可以作为锁定保护,当它们超出范围时解锁它们的互斥锁。

Edit: various clarifications 编辑:各种澄清

Mutex : Add thread safety to shared resources Mutex :为共享资源添加线程安全性
Lock : Add RAII (and possibly extra functionality) to mutex 锁定 :将RAII(可能还有其他功能)添加到互斥锁

Different locks let you lock the mutex in different ways: 不同的锁允许您以不同的方式锁定互斥锁:

  • unique_lock: exclusive access to resource (for write) unique_lock:对资源的独占访问(用于写入)
  • shared_lock: shared access to resource (for simultaneous reads) shared_lock:对资源的共享访问(用于同时读取)
  • scoped_lock: same as unique_lock, but with less features scoped_lock:与unique_lock相同,但功能较少

scoped_lock is a bare bone exclusive lock that is locked when constructed and unlocked when destroyed. scoped_lock是一个裸骨独占锁,在构造时锁定,在销毁时解锁。 unique_lock and shared_lock are exclusive and shared locks respectively that are also locked and unlocked with their default constructor and destructor. unique_lockshared_lock分别是独占锁和共享锁,它们也使用默认构造函数和析构函数锁定和解锁。 However, they also provide extra functionality. 但是,它们还提供额外的功能。 For example, you can try to luck them , or you can unlock them before they are destroyed. 例如,你可以尝试运气 ,或者你可以在它们被销毁之前解锁它们。

So a typical use case would be to use a shared_lock for shared access (when multiple threads read the same resource), and use a unique_lock or a scoped_lock for exclusive access (depending on if you need the extra features of unique_lock or not). 因此,典型的用例是使用shared_lock进行共享访问(当多个线程读取相同的资源时),并使用unique_lockscoped_lock进行独占访问(取决于您是否需要unique_lock的额外功能)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM