确保当前线程持有 C++11 互斥锁

Posted

技术标签:

【中文标题】确保当前线程持有 C++11 互斥锁【英文标题】:Ensuring that current thread holds a lock on a C++11 mutex 【发布时间】:2015-05-03 17:55:28 【问题描述】:

有没有办法判断 C++11 中的当前线程是否持有互斥锁?特别是我想确保类中的某些函数只在调用线程持有对象的锁(通过std::lock_guardstd::unique_lock或类似的东西)时被调用,std::mutex是一个成员变量.

为避免在对象被广泛使用时重复锁定和解锁,锁定mutex的责任需要由调用者负责,并且不能在每个单独的函数中,如果当前线程没有在调用任何这些函数时锁定mutex,我想抛出异常。

似乎我不能只使用std::try_lock,然后根据需要进行解锁,因为如果当前线程已经持有锁,std::try_lock 的行为是未定义的。

【问题讨论】:

“我似乎不能只使用std::try_lock,然后根据需要使用unlock,因为如果当前线程已经持有锁,std::try_lock 的行为是未定义的。 " - 如果您切换到 recursive_mutex,则不会。如果您使用 pthreads,PTHREAD_MUTEX_ERRORCHECK 是另一种选择 - 如果您没有收到错误,throw 【参考方案1】:

我建议这样做的方法是让只能在持有互斥锁时调用的函数引用std::unique_lockstd::lock_guard。对于unique_lock,您可能还想断言它实际上持有锁。

这将利用编译器来强制执行您的要求。

大概这些函数是您的类的内部/私有函数,并且您有面向用户的函数获取锁然后调用这些函数。如果是这样,有一个额外的参数不会污染面向用户的 API。

类似的东西:

// public
void A::public_function() 
   std::lock_guard<std::mutex> l(m_mutex);
   // ... do stuff
   b(l);
   // ... do more stuff


// private
void A::b(std::lock_guard const& l) 
   // ... do stuff that requires holding the mutex

如果您需要改用unique_lock,只需在您的函数中断言l.owns_lock() 为真(以防您想抛出异常)。

我对递归互斥锁的经验是,它们使您很容易不认真对待您的锁定策略和所有权。而且他们以后可能会咬你。请参阅this 帖子。

【讨论】:

我不(完全)同意最后的说法。是的,盲目地使用递归互斥锁来使事情变得简单是一件坏事。但是如果你从一个深思熟虑的锁策略开始,并且递归互斥锁是最合适的,那么你应该使用它们。您的解决方案只会污染您的函数 API(即使它只是内部的)。【参考方案2】:

只需在代码中使用recursive mutex 并锁定/解锁,就像没有上层锁定保证一样。然后将mutex 也提供给可以使用(或不使用)它的调用代码。

最重要的是,如果上层没有锁定,您的代码仍然可以完美运行,尽管速度可能会降低。如果上层确实锁定了,这只不过是检查它是否拥有锁定和 refcount 递增/递减,与您计划执行的开销类似。

C++ 标准库中(目前)没有定义接口,允许您检查互斥锁是否被锁定并且您是所有者。

【讨论】:

谢谢。为读者提供更多信息(递归互斥体在某些情况下可能适用):***.com/questions/2415082/when-to-use-recursive-mutex

以上是关于确保当前线程持有 C++11 互斥锁的主要内容,如果未能解决你的问题,请参考以下文章

如何判断有另一个线程试图持有互斥锁?

Objective-c 中的锁

[C++11 多线程同步] --- 互斥锁

C语言之简单使用互斥锁条件锁实现生产者消费者模型操作

读写锁概述

[C++11 多线程同步] --- 互斥锁