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

Abh*_*yal 1 c++ concurrency multithreading mutex c++17

我有一个由 a 保护的资源类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);
    });
}
Run Code Online (Sandbox Code Playgroud)

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

一种解决方案是写下所有读/写函数的非互斥集,并且仅在批处理上下文中调用它们,而不是在外部。但此类资源访问函数的数量很大,因此增加了维护量并可能引入错误。

寻找替代方案来解决这个问题。

Qui*_*mby 7

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