【问题标题】:c++: mutex, guards and function callsc++:互斥体、守卫和函数调用
【发布时间】:2015-11-15 16:29:45
【问题描述】:

我想知道。当我使用std::mutex _lock 并且想依靠守卫释放它时,我可以这样使用它吗?

class MyClass{
private:
    mutable std::mutex _lock;
    void subroutine(){/*...*/}
public:
    void foo(){
        std::lock(_lock);std::lock_guard<std::mutex> g(_lock, std::adopt_lock);
        subroutine();
        //require I still have the lock here
        //...
        return; //g goes out of scope ==> _lock is released
    }
};

或者对subroutine 的调用是否已经导致锁被释放?如果是后者,我的选择是什么?

更新

这个案子呢?

class MyClass{
private:
    mutable std::mutex _lock;
public:
    void subroutine(){ //can be called on its own
        std::lock(_lock);std::lock_guard<std::mutex> g(_lock, std::adopt_lock);
        /*...*/
    }
    void foo(){
        std::lock(_lock);std::lock_guard<std::mutex> g(_lock, std::adopt_lock);
        subroutine();
        //require I still have the lock here
        //...
        return; //g goes out of scope ==> _lock is released
    }
};

【问题讨论】:

    标签: c++ concurrency scope locking mutex


    【解决方案1】:

    对子例程的调用不会导致锁被释放。 当 std::lock_guard 对象超出范围时(正如您在评论中提到的那样),线程对 _lock 的锁定被释放。

    void foo(){
        std::lock_guard<std::mutex> lg{_lock}; // lock the mutex
        subroutine(); // lock is held here during this call
        // so subroutine must not attempt to lock the mutex _lock!
        return; // lg goes out of scope => its destructor is called which releases the lock on _lock
    }
    

    要回答您的第二个问题,当 foo 获取 _lock 上的锁然后调用子例程时,您会遇到问题,该子例程再次尝试锁定 _lock。线程无法获取已持有锁的互斥锁。我会重新考虑你的班级设计。如果你绝对必须有这个设计,你可以做类似的事情

    void subroutine(bool called_from_foo = false)
    {
        if(!called_from_foo)
            std::lock_guard<std::mutex> lg{_lock};
        /* ... */
    }
    
    void foo()
    {
        std::lock_guard<std::mutex> lg{_lock};
        subroutine(true);
        /* ... */
        return;
    }
    

    虽然我不推荐这样做,因为它很容易以错误的方式使用子例程,导致程序中出现未定义的行为。

    如果您发现自己必须在函数之间传递锁的所有者,我会看看 std::unique_lock,因为这种类型是可移动的。

    【讨论】:

    • 如果subroutine 是公开的并且还执行std::lock(_lock);std::lock_guard&lt;std::mutex&gt; g(_lock, std::adopt_lock);,这会改变吗? (见上面的编辑)
    • 我有点茫然,为什么有人会这样编码。它似乎做的是尝试再次锁定互斥锁 - 这将导致错误或死锁,除非_lockrecursive_mutex。以这种方式使用递归互斥体具有非常糟糕的代码气味。你可能想看看你的类设计。
    猜你喜欢
    • 1970-01-01
    • 2013-07-07
    • 2021-06-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-04-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多