有时编写的函数需要在进入该函数之前锁定一个或多个互斥锁。如果未指定此要求,则可以在进入之前不获取相关锁的情况下调用该函数,这可能会产生灾难性的后果。
现在,可以在函数的文档中指定类似的内容,但我真的不喜欢这样。
我正在考虑在函数的前提条件中指定它(进入函数时断言),但条件应该是什么?
即使 C++11 中的 std::mutex 确实有一个 has_lock() 函数,仍然不能保证我是那个拥有锁的人。
有时编写的函数需要在进入该函数之前锁定一个或多个互斥锁。如果未指定此要求,则可以在进入之前不获取相关锁的情况下调用该函数,这可能会产生灾难性的后果。
现在,可以在函数的文档中指定类似的内容,但我真的不喜欢这样。
我正在考虑在函数的前提条件中指定它(进入函数时断言),但条件应该是什么?
即使 C++11 中的 std::mutex 确实有一个 has_lock() 函数,仍然不能保证我是那个拥有锁的人。
如果您真的不想使用递归互斥锁,并且您的目标是确定当前线程是否持有互斥锁而不尝试获取它,那么定义互斥锁包装器可能是最简单的解决方案。这是一个狂野的镜头:
#include <thread>
#include <mutex>
#include <iostream>
using namespace std;
template<typename M>
struct mutex_wrapper
{
void lock()
{
m.lock();
lock_guard<mutex> l(idGuardMutex);
threadId = this_thread::get_id();
}
void unlock()
{
lock_guard<mutex> l(idGuardMutex);
threadId = thread::id();
m.unlock();
}
bool is_held_by_current_thread() const
{
lock_guard<mutex> l(idGuardMutex);
return (threadId == this_thread::get_id());
}
private:
mutable mutex idGuardMutex;
thread::id threadId;
M m;
};
这是一个如何使用它的简单示例:
int main()
{
cout << boolalpha;
mutex_wrapper<mutex> m;
m.lock();
cout << m.is_held_by_current_thread() << endl;
m.unlock();
cout << m.is_held_by_current_thread() << endl;
}
我认为您的困境的答案就是不要使用外部互斥锁。如果一个类管理需要同步的资源,那么它应该使用内部互斥锁并自己处理所有同步。外部互斥锁很危险,因为它使您面临死锁和非同步访问的可能性。
从评论中,听起来您正在努力解决的问题是重构同步集合。您想将一些代码移出类,但该代码必须同步。这是一个如何做到这一点的示例:
class MyCollection {
private:
std::list<Foo> items;
std::mutex lock;
public:
template <class F> void ForEach( F function )
{
std::lock_guard<decltype(this->lock) guard( this->lock );
for( auto item : items )
function( *item );
}
};
这种技术仍然存在死锁的可能性。由于函数参数是一个任意函数,它可能会访问集合并因此获取互斥锁。另一方面,如果“ForEach”应该是只读的,则可能需要这种行为。