Laj*_*agy 5 c++ multithreading deadlock locking
这个设计问题一次又一次地出现,我仍然没有一个很好的解决方案.它可能会变成一种设计模式;)但是,它似乎非常特定于C++(缺少垃圾收集).无论如何,这是问题所在:
我们有一个父对象,它保持对子对象的引用.父母的州取决于其子女的州(某些总和).为了通知其子女的状态变化,它会向他们传递对自己的引用.(在另一个变体中,它向它们传递一个回调,子进程可以调用它来通知父进程.这个回调是一个闭包,它保持对父进程的引用.)应用程序是多线程的.现在,这个设置是整个大黄蜂的潜在竞争条件和死锁的巢.要理解原因,这是一个天真的实现:
class Parent {
public:
Parent() {
children_["apple"].reset(new Child("apple", this));
children_["peach"].reset(new Child("peach", this));
}
~Parent() {
}
void ChildDone(const string& child) {
cout << "Child is DONE: " << child << endl;
}
private:
map<string, linked_ptr<Child> > children;
};
class Child {
public:
Child(const string& name, Parent* parent)
: name_(name), parent_(parent), done_(false) {}
Foo(int guess) {
if (guess == 42) done_ = true;
parent->ChildDone(name_);
}
private:
const string name_;
Parent* parent_;
bool done_;
};
Run Code Online (Sandbox Code Playgroud)
潜在问题:
我只是触及了表面,但人们可以想到其他潜在的问题.
我正在寻找的是关于如何在线程,锁定和动态添加/删除子项时处理父类的干净破坏的一些建议.如果有人提出了一个在多线程部署下强大的优雅解决方案,请分享.这里的关键字是健壮的:很容易设计一个带有一些巨大警告的结构(子节点从不调用父节点,父节点从不调用子节点,没有单独的线程用于回调等),挑战在于对程序员的限制很少尽可能.
如果父级和子级中都有锁(很可能在多线程的非平凡应用程序中),则锁定顺序将成为一个问题:父级调用子级上的方法,而子级又会经历状态转换并尝试通知父级:死锁。
我不清楚为什么通知家长会导致僵局,除非
这是很多如果。这是一种自然有问题的设计:一个线程 (A) 持有锁,并等待另一个线程 (B) 执行某些操作。
没有什么神奇的解决方案可以避免这个问题——你只需避免它。最好的答案可能是不要从单独的线程向父级发回信号;或者,区分在已持有父锁的情况下将调用或不会调用的信号。
在销毁父级期间,它必须留意来自其子级的持续回调。特别是如果这些回调是在单独的线程中触发的。如果不是,则在调用回调时它可能已经消失。
这里的技巧可能是子级应该有一个方法(可能是析构函数),该方法保证在返回后,子级将不再进行回调。当父对象被销毁时,它会为其每个子对象调用该方法。
我知道您要求“尽可能少的限制”,但实际上,在多线程环境中工作时,您必须制定规则来防止死锁和竞争。
归档时间: |
|
查看次数: |
675 次 |
最近记录: |