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

时间:2017-06-20 11:54:30

标签: c++ multithreading language-lawyer mutex

C ++ 17引入了std::shared_mutex类型。我一直在查看CppReference上的文档,对于产生未定义行为的案例特别感兴趣。

在阅读两​​种解锁方法(一种用于释放独占所有权,一种用于释放共享所有权)时,我发现文档在某种程度上有点模糊。

对于std::shared_mutex::unlock_shared,文档说明(强调我的):

  

互斥锁必须由共享模式中的当前执行线程锁定,否则,行为未定义。

清楚地表明,调用unlock_shared之前必须先调用lock_shared,因为这是在共享模式下锁定互斥锁的唯一方法。

对于std::shared_mutex::unlock,文档说明:

  

互斥锁必须由当前执行线程锁定,否则行为未定义。

在调用unlock之前,没有提到当前执行线程必须保持的访问级别。这让我想知道它是否也能够释放共享所有权以及独家所有权。

我的问题:通过调用std::shared_mutex代替unlock来释放unlock_shared的共享所有权是未定义的行为吗?

如果可能的话,我希望C ++标准中引用一个明确证实或否认上述场景中未定义行为的引用。

2 个答案:

答案 0 :(得分:2)

我们有[thread.mutex.requirements.mutex]

  

表达式m.unlock()应格式正确,并具有以下语义:

     

需要:调用线程应拥有互斥锁。

     

效果:释放调用线程对互斥锁的所有权。

     

返回类型:void。

     

同步:此操作与后续锁定操作同步,后者获取对同一对象的所有权。

     

引发:没什么。

因此,只要线程拥有互斥锁,无论它是否处于共享模式,unlock都将释放互斥锁的线程所有权。

答案 1 :(得分:2)

我没有通过标准来验证其内容,但the original proposal明确指出lock / unlocklock_shared / {{1调用应该配对:

unlock_shared

它还明确指出存在这种分离是因为在Windows上实现SRWLOCK的方式:

  

此外,某些操作系统(例如Windows)有所不同   用于解锁共享和解锁唯一的名称。用于   C ++ API中的不同名称允许更有效的绑定   这样的操作系统API。

如果标准没有明确提到这一点,那很可能是标准中的缺陷。无论这是有意的,实际上在Windows上随MSVC一起提供的所有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 实现都不会像那样要求正确配对锁定解锁调用。

在POSIX系统上,shared_mutexunlock确实映射到单个函数unlock_shared,因此两者最有可能在那里相同。这是一个不应该依赖的副作用。

在Windows 7上pthread_rwlock_unlock使用最低有效位将锁定标记为由读取器或写入器锁定。函数SRWLOCK清除该位,破坏锁定,而unlock仅在最后一个读取器离开锁定时清除它。以下示例显示了锁如何更改其状态:

unlock_shared

即使有另一位持有锁的读者,最终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) 也可以获取互斥锁。之后lock被认为被2位读者锁定,因此更多读者可以进入锁定状态。因此,在上面的序列std::shared_mutex已将互斥锁定在共享所有权模式中,而不是排他性作为误用的副作用。