我听说递归互斥锁是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;
}
如果do_something()
不是递归的,函数m
将会死锁,但除非我有两种执行检查的方法,否则会有什么替代方法。
正如上面的链接所暗示的那样,这个选择最终会使这个类更复杂,是否有一个更简洁的解决方案,不需要递归的互斥锁?或者是一个递归的互斥体,有时候 邪恶?
答案 0 :(得分:4)
如果您需要将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的回答,将锁定引用传递给内部函数只是为了避免未来维护者的遗忘; - )。
只有在调用一个方法时才需要递归锁定,这个方法也会锁定另一个方法(具有相同的锁定),但需要进行一些重构(将常用功能移动到不锁定的私有方法中,但将锁定引用作为锁定引用“提醒”;-)消除了这种需要。
不需要重复任何功能 - 只需将公共函数暴露给“半空壳”,这些函数也需要(以非锁定的方式,因为已经获取了锁)从其他函数中获得完全相同(锁定)的功能。 “执行锁定然后调用这些私有函数,这些函数执行所有必要的工作。类中需要这些功能但想要自己进行锁定的其他函数可以直接调用私有函数。
答案 1 :(得分:0)
将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,它返回的任何值都会在您查看时过期,这对于没有锁定权限的消费者来说非常无用。