如何断言如果一个std :: mutex被locking?

使用GCC 4.8.2(在Linux / Debian / Sid 64位上)或GCC 4.9(在C ++ 11中) – 我有一些互斥锁

std::mutex gmtx; 

实际上,它是某个Foo类中的static成员,它包含下面的alphabeta方法。

它被locking在alpha

 void alpha(void) { std::lock_guard<std::mutex> g(gmtx); beta(void); // some other work } 

我想检查beta确实gmtx被locking:

 void beta(void) { assert (gmtx.is_locked()); // some real work } 

(注意, is_locked只在assert里面调用…可能是非常低效的,甚至有时是不准确的)

当然,我还有其他的函数叫做beta ,例如

 void gamma(void) { std::lock_guard<std::mutex> g(gmtx); beta(); // some other work } 

is_locked不存在….我应该如何定义它? (实际上,我想确保互斥锁已经被某个[间接]调用者locking在同一个线程中…)

(我想用assert来testing的原因是beta可以在别处调用)

我不能使用try_lock (除非使用recursion互斥体),因为在一般情况下,它会locking一个已经被locking的互斥体(被调用者locking在相同的线程中),这不仅是未定义的行为,而且完全阻塞。

除非我真的需要,否则我想避免recursion互斥体(比普通的互斥体更昂贵)。


注意:真正的程序有点复杂。 实际上,所有的方法都是在“项目”上保持命名双向关系的类。 所以我在这个类里面有一个从项目到名称的映射,另一个从名称到项目。 beta将是内部方法增加一个真正的命名, alphagamma将是方法寻找或添加一个项目的名称,或由其项目的名称。

PS:真正的节目还没有发布,但应该成为MELT的一部分 – 未来的监控 ; 你可以从这里 (一个临时的位置)下载它(阿尔法阶段,很多马车)

std::unique_lock<L>具有owns_lock成员函数(相当于你所说的is_locked )。

 std::mutex gmtx; std::unique_lock<std::mutex> glock(gmtx, std::defer_lock); void alpha(void) { std::lock_guard<decltype(glock)> g(glock); beta(void); // some other work } void beta(void) { assert(glock.owns_lock()); // or just assert(glock); // some real work } 

编辑:在这个解决方案中,所有的锁操作都应该通过unique_lock glock而不是'raw'mutex gmtx来执行。 例如, alpha成员函数被lock_guard<unique_lock<mutex>> (或者简单的lock_guard<decltype(glock)> )重写。

严格来说,问题是直接检查std::mutex的锁定。 但是,如果允许将其封装在新类中,则很容易这样做:

 class mutex : public std::mutex { public: #ifndef NDEBUG void lock() { std::mutex::lock(); m_holder = std::this_thread::get_id(); } #endif // #ifndef NDEBUG #ifndef NDEBUG void unlock() { m_holder = std::thread::id(); std::mutex::unlock(); } #endif // #ifndef NDEBUG #ifndef NDEBUG /** * @return true iff the mutex is locked by the caller of this method. */ bool locked_by_caller() const { return m_holder == std::this_thread::get_id(); } #endif // #ifndef NDEBUG private: #ifndef NDEBUG std::thread::id m_holder; #endif // #ifndef NDEBUG }; 

请注意以下几点:

  1. 在释放模式下,除std::mutex之外,其构造/销毁(对于互斥对象来说这不是个问题)除外。
  2. m_holder成员只能在获取互斥锁和释放互斥锁之间访问。 因此互斥体本身就是m_holder的互斥体。 对std::thread::id类型的假设非常弱, locked_by_caller将正常工作。
  3. 其他STL组件,例如std::lock_guard是模板,所以它们可以很好地适用于这个新类。

你可以使用一个recursive_mutex ,它可以在同一个线程上多次被锁定。 注意:如果是我的代码,我会重构它,以便我不需要recursive_mutex ,但它会解决您的问题。

因为你的问题是“如果一个互斥锁被锁定,如何断言”,你可以使用assert(!mtx.try_lock()); 。 当然,你只能断言互斥锁被任何线程锁定,而不是由这个线程锁定。

尝试原子 (例如atomic<bool>atomic<int> ),它有一个很好的加载函数,可以做你想做的,以及像compare_exchange_strong这样的其他很好的函数。

那么,如果断言的开销真的不是问题,那么你可以从另一个线程中调用try_lock()来保证它的行为被很好的定义:

 void beta(void) { assert(std::async(std::launch::async, [] { return gmtx.try_lock(); }) .get() == false && "error, beta called without locking gmtx"); // some real work }