简体   繁体   English

在共享模式下锁定的std :: shared_mutex上调用unlock

[英]Call unlock on std::shared_mutex that is locked in shared mode

C++17 introduces the std::shared_mutex type. C ++ 17引入了std::shared_mutex类型。 I have been looking at the documentation over on CppReference with a particular interest for cases that produce undefined behavior. 我一直在查看有关CppReference的文档,特别感兴趣的是产生未定义行为的情况。

While reading through both unlock methods (one for releasing exclusive ownership, one for releasing shared ownership), I've noticed the documentation is a little vague on one occasion. 在阅读两种解锁方法(一种用于释放独占所有权,一种用于释放共享所有权)的同时,我注意到文档在某种程度上有点模糊。

For std::shared_mutex::unlock_shared , the documentation states (emphasis mine): 对于std::shared_mutex::unlock_shared ,文档说明(强调我的):

The mutex must be locked by the current thread of execution in shared mode , otherwise, the behavior is undefined. 必须在共享模式下由当前执行线程锁定互斥锁,否则,行为未定义。

It is clearly indicated that a call to unlock_shared must be preceded by a call to lock_shared as that is the only way to lock the mutex in shared mode. 清楚地表明,对unlock_shared的调用必须先调用lock_shared因为这是在共享模式下锁定互斥锁的唯一方法。

For std::shared_mutex::unlock , the documentation states: 对于std::shared_mutex::unlock ,文档说明:

The mutex must be locked by the current thread of execution, otherwise, the behavior is undefined. 必须通过当前执行线程锁定互斥锁,否则,行为未定义。

There is no mention of the level of access the current thread of execution must hold before calling unlock . 在调用unlock之前,没有提到当前执行线程必须保持的访问级别。 This made me wonder if it is also capable of releasing shared ownership as well as exclusive ownership. 这让我想知道它是否也能够释放共享所有权以及独家所有权。

My question: is it undefined behavior to release shared ownership of a std::shared_mutex with a call to unlock instead of unlock_shared ? 我的问题:是否通过调用unlock而不是unlock_shared释放std::shared_mutex共享所有权是未定义的行为?

If possible, I'd like a quote from the C++ standard that explicitly confirms or denies undefined behavior in the aforementioned scenario. 如果可能的话,我想从C ++标准中引用一个明确证实或否认上述场景中未定义行为的引用。

Per [thread.mutex.requirements.mutex] we have 我们有[thread.mutex.requirements.mutex]

The expression m.unlock() shall be well-formed and have the following semantics: 表达式m.unlock()应该是格式良好的,并具有以下语义:

Requires : The calling thread shall own the mutex. 要求 :调用线程应拥有互斥锁。

Effects : Releases the calling thread's ownership of the mutex. 效果 :释放调用线程对互斥锁的所有权。

Return type: void. 返回类型:void。

Synchronization : This operation synchronizes with subsequent lock operations that obtain ownership on the same object. 同步 :此操作与后续锁定操作同步,后者获取对同一对象的所有权。

Throws : Nothing. 投掷 :没什么。

So, as long as the thread owns the mutex ,whether it is in shared mode or not, unlock will release the threads ownership of the mutex. 因此,只要线程拥有互斥锁,无论它是否处于共享模式, unlock都将释放互斥锁的线程所有权。

I didn't go through the standard to verify what exactly it says, but the original proposal clearly states that lock / unlock and lock_shared / unlock_shared calls should be paired: 我没有通过标准来验证它究竟是什么,但原始提案明确指出应该配对lock / unlocklock_shared / unlock_shared调用:

shared_mutex  | Semantics
--------------+---------------------------------------------
lock          | Lock the mutex in unique ownership mode
unlock        | unlock the mutex from unique ownership mode
lock_shared   | Lock the mutex in shared ownership mode
unlock_shared | unlock the mutex from shared ownership mode

It also explicitly states that this separation exists because of how SRWLOCK is implemented on Windows: 它还明确指出存在这种分离是因为在Windows上如何实现SRWLOCK

Additionally, some operating systems (eg Windows) have different names for unlocking shared vs unlocking unique as well. 此外,某些操作系统(例如Windows)具有不同的名称,用于解锁共享和解锁唯一。 Use of different names in the C++ API allows for a more efficient binding to such OS API's. 在C ++ API中使用不同的名称可以更有效地绑定到此类OS API。

If standard does not mention this somewhere explicitly, it is most likely a defect in the standard. 如果标准没有明确提到这一点,那很可能是标准中的缺陷。 Regardless of where this was intentional, in practice all shared_mutex implementations shipped with MSVC on Windows will not work like that as they require pairing lock-unlock calls properly. 无论这是故意的,实际上在Windows上随MSVC一起提供的所有shared_mutex实现都不会那样,因为它们需要正确配对锁定解锁调用。

On POSIX systems both unlock and unlock_shared are indeed mapped to a single function pthread_rwlock_unlock , so both are most likely to be equivalent there. 在POSIX系统上, unlockunlock_shared确实映射到单个函数pthread_rwlock_unlock ,因此两者最有可能在那里相同。 This is a side effect that should not be relied upon. 这是一个不应该依赖的副作用。


On Windows 7 SRWLOCK uses the least significant bit to mark lock as locked by either reader or writer. 在Windows 7上, SRWLOCK使用最低有效位将锁定标记为由读取器或写入器锁定。 Function unlock clears that bit, corrupting the lock, while unlock_shared only clears it if the last reader leaves the lock. 功能unlock清除该位,破坏锁定,而unlock_shared仅在最后一个读取器离开锁定时清除它。 Following example shows how the lock changes its state: 以下示例显示了锁如何更改其状态:

mtx.lock_shared(); // 0x11 - 1 reader, locked (shared)
mtx.lock_shared(); // 0x21 - 2 readers, locked (shared)
mtx.unlock();      // 0x20 - 2 readers, unlocked (invalid state)
mtx.lock();        // 0x21 - 2 readers, locked (shared)

Final lock is able to acquire the mutex even through there is another reader holding the lock. 即使通过另一个拿着锁的读卡器,最终lock也能够获取互斥锁。 After that std::shared_mutex is considered to be locked by 2 readers, so more readers can enter the lock. 之后, std::shared_mutex被认为被2位读者锁定,因此更多读者可以进入锁定状态。 So in the sequence above lock has locked the mutex in shared ownership mode, instead of exclusive as a side effect of misusage. 因此,在上面的序列中, lock已将互斥lock锁定在共享所有权模式中,而不是排他性作为误用的副作用。

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

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