的考虑以下几点:锁定对相互引用资源
// There are guys:
class Guy {
// Each guy can have a buddy:
Guy* buddy; // When a guy has a buddy, he is his buddy's buddy, i.e:
// assert(!buddy || buddy->buddy == this);
public:
// When guys are birthed into the world they have no buddy:
Guy()
: buddy{}
{}
// But guys can befriend each other:
friend void befriend(Guy& a, Guy& b) {
// Except themselves:
assert(&a != &b);
// Their old buddies (if any), lose their buddies:
if (a.buddy) { a.buddy->buddy = {}; }
if (b.buddy) { b.buddy->buddy = {}; }
a.buddy = &b;
b.buddy = &a;
}
// When a guy moves around, he keeps track of his buddy
// and lets his buddy keep track of him:
friend void swap(Guy& a, Guy& b) {
std::swap(a.buddy, b.buddy);
if (a.buddy) { a.buddy->buddy = &a; }
if (b.buddy) { b.buddy->buddy = &b; }
}
Guy(Guy&& guy)
: Guy()
{
swap(*this, guy);
}
Guy& operator=(Guy guy) {
swap(*this, guy);
return *this;
}
// When a Guy dies, his buddy loses his buddy.
~Guy() {
if (buddy) { buddy->buddy = {}; }
}
};
一切都很好,到目前为止,但现在我要当哥们在不同的线程中使用这个工作。没问题,我们只是坚持std::mutex
在Guy
:
class Guy {
std::mutex mutex;
// same as above...
};
现在我只是有关联或取消关联他们两人之前锁定这两个家伙的互斥。
这是我难住的地方。下面是失败的尝试(使用析构函数为例):
僵局:
~Guy() { std::unique_lock<std::mutex> lock{mutex}; if (buddy) { std::unique_lock<std::mutex> buddyLock{buddy->mutex}; buddy->buddy = {}; } }
当两个哥们在大约在同一时间被破坏,这可能是他们每个人锁定自己互斥,然后试图锁定他们的伙伴的互斥体,从而导致僵局。
竞争条件:
好了,所以我们只需要手动或使用
std::lock
锁定一致的顺序互斥:不幸的是~Guy() { std::unique_lock<std::mutex> lock{mutex, std::defer_lock}; if (buddy) { std::unique_lock<std::mutex> buddyLock{buddy->mutex, std::defer_lock}; std::lock(lock, buddyLock); buddy->buddy = {}; } }
,去好友的互斥体,我们必须访问
buddy
哪些在这一点上不受任何锁保护,并且可能正在从另一个线程中修改,这是一种竞争条件。不可扩展:
正确性可以能获得具有全局mutex:
static std::mutex mutex; ~Guy() { std::unique_lock<std::mutex> lock{mutex}; if (buddy) { buddy->buddy = {}; } }
但是,这是不可取的性能和可扩展性的原因。
那么这是可能做到没有全局锁?怎么样?
我想你需要分开“好友”和“家伙”的关注。即一个名为“Guys”的新类,其中包含对零个,一个或两个家伙的引用。 –
@RichardHodges如何帮助? “家伙”和每个“家伙”之间会存在同样的问题。 –
我有点赞同@RichardHodges。从概念上讲,似乎需要同步的是“Guy”而非“Guy”本身之间的关系。这可以通过'Guy'之间共享的互斥体来完成,每当伙伴关系被切断时(无论是新朋友“朋友”结识还是被破坏),锁定都会被锁定。 – bnaecker