【问题标题】:Trade off between a recursive mutexes V a more complex class?在递归互斥体 V 更复杂的类之间进行权衡?
【发布时间】:2010-08-23 02:40:52
【问题描述】:

我听说递归互斥锁是 evil,但我想不出没有它的最佳方法。

class Object {
public:
    bool check_stuff() {
        lock l(m);

        return /* some calculation */;
    }
    void do_something() { 
        lock l(m);

        if (check_stuff()) {
            /* ... */
        }
        /* ... */
    }
private:
    mutex m;
}

如果m 不是递归的,函数do_something() 将死锁,但有什么替代方法,除非我有两种方法来执行检查,其中一种不锁定。

正如上面的链接所暗示的那样,这种选择最终会使类更复杂,是否有不需要递归互斥锁的更简洁的解决方案?或者递归互斥体有时不是邪恶的?

【问题讨论】:

    标签: c++ thread-safety mutex


    【解决方案1】:

    如果您需要将check_stuff 公开(以及当前调用它的do_something),只需简单的重构即可完成,无需重复任何计算:

    class Object {
    public:
        bool check_stuff() {
            lock l(m);
    
            return internal_check_stuff(l);
        }
        void do_something() { 
            lock l(m);
    
            if (internal_check_stuff(l)) {
                /* ... */
            }
            /* ... */
        }
    private:
        mutex m;
        bool internal_check_stuff(lock&) {
            return /* some calculation */;
        }
    }
    

    (根据@Logan 的回答,将锁引用传递给内部函数只是避免未来维护者健忘的好主意;-)。

    只有当你调用一个从另一个锁的方法时才需要递归锁(使用相同的锁),但需要进行一些重构(将通用功能移动到不锁定但将锁引用作为私有方法的私有方法中) “提醒”;-) 消除了这种需要。

    不需要重复任何功能 - 只需将公开功能与其他功能完全相同的(锁定)功能(以非锁定方式,因为已获得锁)公开为“半空外壳” " 执行锁定然后调用这样的私有函数,这些函数完成所有必要的工作。类中其他需要此类功能但又想明确自己加锁的函数,直接调用私有函数即可。

    【讨论】:

    • 感谢亚历克斯,特别是为了如此清晰。我认为这是我将采用的方法。
    【解决方案2】:

    将 check_stuff 设为私有,而不是锁定,然后简单地从 do_something 调用它并锁定互斥锁。一个使这更安全的常用习惯用法是将锁的引用传递给 check_stuff:

     bool check_stuff(const lock&)
     {
        return /* some calculation */;
     }
    
     void do_something()
     {
        lock l(m);
        if(check_stuff(l)) { // can't forget to lock, because you need to pass it in to call check_stuff
          ...
        }
     }
    

    check_stuff 无论如何都不应该锁定并返回 bool,它返回的任何值在您查看时都已过期,这对于无法访问锁定的消费者来说毫无用处。

    【讨论】:

    • 谢谢洛根。在我的特殊情况下,check_stuff 的外部调用者只是在 UI 上显示状态,因此它的有效性并不重要。但我确实理解您的评论是完全正确的,只要该结果是准确的。
    猜你喜欢
    • 2010-09-16
    • 1970-01-01
    • 1970-01-01
    • 2018-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多