在共享模式下锁定的 std::shared_mutex 上调用解锁
Call unlock on std::shared_mutex that is locked in shared mode
C++17 引入了 std::shared_mutex
type. I have been looking at the documentation over on CppReference,特别关注产生未定义行为的情况。
在通读两种解锁方法(一种用于释放独占所有权,一种用于释放共享所有权)时,我注意到文档有一次有点含糊。
对于 std::shared_mutex::unlock_shared
,文档说明(强调我的):
The mutex must be locked by the current thread of execution in shared mode, otherwise, the behavior is undefined.
明确指出调用 unlock_shared
之前必须调用 lock_shared
,因为这是在共享模式下锁定互斥锁的唯一方法。
对于 std::shared_mutex::unlock
,文档指出:
The mutex must be locked by the current thread of execution, otherwise, the behavior is undefined.
没有提及当前执行线程在调用 unlock
之前必须持有的访问级别。这让我想知道它是否也能够释放共享所有权和独占所有权。
我的问题: 通过调用 unlock
而不是 unlock_shared
来释放 std::shared_mutex
的共享所有权是未定义的行为吗?
如果可能的话,我想要引用 C++ 标准中明确确认或否认上述场景中未定义行为的内容。
根据 [thread.mutex.requirements.mutex] 我们有
The expression m.unlock()
shall be well-formed and have the following semantics:
Requires: The calling thread shall own the mutex.
Effects: Releases the calling thread's ownership of the mutex.
Return type: void.
Synchronization: This operation synchronizes with subsequent lock operations that obtain ownership on the same object.
Throws: Nothing.
因此,只要线程拥有互斥锁,无论是否处于共享模式,unlock
都会释放线程对互斥锁的所有权。
我没有通过标准来验证它到底说了什么,但是the original proposal明确指出lock
/unlock
和lock_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
它还明确指出,由于 SRWLOCK
在 Windows 上的实现方式,因此存在这种分离:
Additionally, some operating systems (e.g. Windows) have different
names for unlocking shared vs unlocking unique as well. Use of
different names in the C++ API allows for a more efficient binding to
such OS API's.
如果标准没有在某处明确提及这一点,则很可能是标准中的缺陷。不管这是故意的,实际上所有 Windows 上 MSVC 附带的 shared_mutex
实现都不会像那样工作,因为它们 需要 配对 lock-unlock 调用正确。
在 POSIX 系统上,unlock
和 unlock_shared
确实映射到一个函数 pthread_rwlock_unlock
,因此两者很可能在那里是等价的。这是不应依赖的副作用。
On Windows 7 SRWLOCK
使用最低有效位将锁标记为已被 reader 或 writer 锁定。函数 unlock
清除该位,破坏锁,而 unlock_shared
仅在最后一个 reader 离开锁时才清除它。以下示例显示锁如何更改其状态:
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)
即使有另一个 reader 持有锁,最终 lock
也能够获取互斥锁。之后std::shared_mutex
被认为被锁定了2readers,所以更多的readers可以进入锁。因此,在上面的序列中,lock
已将互斥体锁定为共享所有权模式,而不是误用的副作用。
C++17 引入了 std::shared_mutex
type. I have been looking at the documentation over on CppReference,特别关注产生未定义行为的情况。
在通读两种解锁方法(一种用于释放独占所有权,一种用于释放共享所有权)时,我注意到文档有一次有点含糊。
对于 std::shared_mutex::unlock_shared
,文档说明(强调我的):
The mutex must be locked by the current thread of execution in shared mode, otherwise, the behavior is undefined.
明确指出调用 unlock_shared
之前必须调用 lock_shared
,因为这是在共享模式下锁定互斥锁的唯一方法。
对于 std::shared_mutex::unlock
,文档指出:
The mutex must be locked by the current thread of execution, otherwise, the behavior is undefined.
没有提及当前执行线程在调用 unlock
之前必须持有的访问级别。这让我想知道它是否也能够释放共享所有权和独占所有权。
我的问题: 通过调用 unlock
而不是 unlock_shared
来释放 std::shared_mutex
的共享所有权是未定义的行为吗?
如果可能的话,我想要引用 C++ 标准中明确确认或否认上述场景中未定义行为的内容。
根据 [thread.mutex.requirements.mutex] 我们有
The expression
m.unlock()
shall be well-formed and have the following semantics:Requires: The calling thread shall own the mutex.
Effects: Releases the calling thread's ownership of the mutex.
Return type: void.
Synchronization: This operation synchronizes with subsequent lock operations that obtain ownership on the same object.
Throws: Nothing.
因此,只要线程拥有互斥锁,无论是否处于共享模式,unlock
都会释放线程对互斥锁的所有权。
我没有通过标准来验证它到底说了什么,但是the original proposal明确指出lock
/unlock
和lock_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
它还明确指出,由于 SRWLOCK
在 Windows 上的实现方式,因此存在这种分离:
Additionally, some operating systems (e.g. Windows) have different names for unlocking shared vs unlocking unique as well. Use of different names in the C++ API allows for a more efficient binding to such OS API's.
如果标准没有在某处明确提及这一点,则很可能是标准中的缺陷。不管这是故意的,实际上所有 Windows 上 MSVC 附带的 shared_mutex
实现都不会像那样工作,因为它们 需要 配对 lock-unlock 调用正确。
在 POSIX 系统上,unlock
和 unlock_shared
确实映射到一个函数 pthread_rwlock_unlock
,因此两者很可能在那里是等价的。这是不应依赖的副作用。
On Windows 7 SRWLOCK
使用最低有效位将锁标记为已被 reader 或 writer 锁定。函数 unlock
清除该位,破坏锁,而 unlock_shared
仅在最后一个 reader 离开锁时才清除它。以下示例显示锁如何更改其状态:
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)
即使有另一个 reader 持有锁,最终 lock
也能够获取互斥锁。之后std::shared_mutex
被认为被锁定了2readers,所以更多的readers可以进入锁。因此,在上面的序列中,lock
已将互斥体锁定为共享所有权模式,而不是误用的副作用。