如果在锁定相同互斥锁的另一个函数中调用,如何禁用互斥锁

How to disable mutex if called within another function locking same mutex

我有一个资源 class 由 std::mutex 保护,其中任何访问它的方法都必须锁定并且只能由单个线程执行。如果单独调用各个方法,这很好用,但现在我需要将这些方法一起批处理。在这种情况下,互斥量只需要被锁定一次,并且这些方法不能再次锁定该互斥量(否则将陷入死锁)。


class Resource {
    mutable std::mutex mtx;
    int value = 10;

    void handleOpStart() const {/* Activate batch mode */ std::cout << "HandleOp activate!"<< std::endl; }
    void handleOpEnd() const {/* Deactivate batch mode */ std::cout << "HandleOp deactivate!"<< std::endl; }
public:
    int read() const  {
        std::lock_guard<std::mutex> lock(mtx);
        handleOpStart(); auto result =  value + 10; handleOpEnd();
        return result;
    }
    void write(int val)  {
        std::lock_guard<std::mutex> lock(mtx);
        handleOpStart(); value = val; handleOpEnd();
    }

    template<typename Fn>
    void batch(Fn fn) {
        std::lock_guard<std::mutex> lock(mtx);
        handleOpStart();
        fn();
        handleOpEnd();
    }

    void print() const {
        std::lock_guard<std::mutex> lock(mtx);
        std::cout << "Value: " << value << std::endl;
    }
};

int main() {
    Resource r;
    r.print();
    r.write(r.read());
    r.print();

    r.batch([&] {
        // will cause deadlock
        auto someVal = r.read();
        auto someOtherVal = 10 + someVal;
        r.write(r.read() + someOtherVal);
    });
}

现在我无法从单个方法中删除互斥量,因为它们可以从外部批处理上下文中单独调用。我不能保留互斥锁,因为它们也可以在其中调用。如果我在 class 中保留一个布尔变量,它在 batch 函数调用中停用互斥锁,那么它也会停用从其他线程调用的其他单个函数,再次破坏目的。

一个解决方案是写下所有 read/write 函数的非互斥集,并且只在批处理上下文中调用它们,而不是在外部调用它们。但此类资源访问功能数量多,增加维护难度,可能引入BUG。

正在寻找解决此问题的替代方案。

这正是 std::recursive_mutex 的用途,它可以从同一线程多次锁定。只有当解锁调用次数与锁定调用次数匹配时才会完全解锁。