我知道我可以在类中使用mutex成员,并将其锁定在每个方法中,以防止多线程环境中的数据竞争。但是,如果类的方法中存在嵌套调用,比如类下面的add_one()和add_two(),这种方法可能会导致死锁。对每个方法使用不同的mutex是一个解决办法。但是,在嵌套调用的情况下,是否有更有原则和优雅的方法来防止死锁呢?
class AddClass {
public:
AddClass& operator=(AddClass const&) = delete; // disable copy-assignment constructor
AddClass(int val) : base(val) {}
int add_one() { return ++base; }
int add_two() {
add_one;
add_one;
return base;
}
private:
int base;
};发布于 2017-01-01 16:08:25
std::recursive_mutex正是为此目的而存在的。
另一种避免递归互斥产生开销的方法是将公共同步接口与私有非同步实现分开:
class AddClass {
public:
AddClass& operator=(AddClass const&) = delete; // disable copy-assignment constructor
AddClass(int val) : base(val) {}
int add_one() {
std::lock_guard<std::mutex> guard{mutex};
return add_one_impl();
}
int add_two() {
std::lock_guard<std::mutex> guard{mutex};
return add_two_impl();
}
private:
int base;
std::mutex mutex;
int add_one_impl() {
return ++base;
}
int add_two_impl() {
add_one_impl();
add_one_impl();
return base;
}
};但是,请注意,这并不总是可能的。例如,如果有一个方法接受回调并在持有锁时调用回调,则回调可能尝试调用类的其他公共方法,并且再次面临双重锁定尝试。
发布于 2017-01-01 16:13:56
发布于 2017-01-01 16:07:01
这方面的一般解决方案称为重入互斥。
虽然在普通互斥锁( lock )上执行“锁”操作的任何尝试都将在互斥锁已经锁定时失败或阻塞,但在递归互斥锁上,只有当锁定线程已经持有该锁时,此操作才会成功。通常,递归互斥锁跟踪它被锁定的次数,并要求在其他线程锁定它之前执行同样多的解锁操作。
C++11标准库中有一个:互斥
https://stackoverflow.com/questions/41416794
复制相似问题