如何在输入函数之前指定需要哪些互斥锁

How to specify what mutex locks are needed before entering a function

本文关键字:输入 函数      更新时间:2023-10-16

有时编写一个函数,要求在进入该函数之前锁定一个或多个互斥锁。如果未指定此要求,则可以在进入之前调用该函数而无需使用相关锁,这可能会产生灾难性后果。

现在,可以在函数文档中指定这样的东西,但我真的不喜欢这样。

我想在函数的前提条件中指定它(输入函数时断言),但条件应该是什么?

即使 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"应该是只读的,则可能需要此行为。