我已经在这个问题上苦苦挣扎了大约24小时,我似乎无法找到解决方法。
假设我有一系列Foo对象:
public class Foo {
public int SomeValue;
public void Execute() {
lock (this) {
SomeValue++;
}
}
}
// Instantiated elsewhere and filled with lots of Foos
private static ConcurrentCollection<Foo> fooCollection;
现在我正在为每个Foo调用Execute(我有一台多核机器):
Parallel.ForEach(fooCollection, foo => foo.Execute());
现在假设我们添加了第二种Foo
:
public class Bar : Foo {
private Foo myFriend;
public new void Execute() {
lock (this) {
SomeValue++;
lock (myFriend) {
myFriend.SomeValue += SomeValue;
}
}
}
}
这个新的Bar
仍会锁定自身以在Execute
期间保持一致性,并递增SomeValue
。但它也会锁定其Foo
朋友,以便在更新myFriend
之前以线程安全的方式更新myFriend.SomeValue
。
我遇到的问题是我可能有Bar
s的循环引用链,例如
bar1.myFriend = bar2; bar2.myFriend = bar1;
在最坏的情况下:
所以,我的问题是:我如何解决这个问题?
有关我的应用的一些实际指标:
Execute()
,其中N =主机上的逻辑核心数。一些警告:
lock
(Monitor.Enter/Exit
),但是可以使用任何线程同步构造(例如状态变量&amp; Interlocked
方法等)。 / LI>
我希望有一些解决这个问题的标准方法,我并不知道。我尝试过各种各样的体操,但每次我写出最糟糕的情况时,僵局总是有潜力。
提前致谢。 :)
答案 0 :(得分:2)
好吧,通常为了避免死锁,我们可以优先考虑资源,所以总是先尝试锁定优先级较高的资源。
在你的情况下,它不像这里那么简单,对象是相同的或派生类型。
因此,解决此问题的一种非常扭曲的方法是为所有实例提供自动增量整数。任何具有更高价值的实例都将被视为具有更高的优先级
类似
foo p1 = this;
foo p2 = myfriend;
if(p1.priority < p2.priority)
{
foo t = p2;
p2 = p1;
p1 = t;
}
lock(p1)
{
lock(p2)
{
// here you can safely increment both p1 & p2 some value.
}
}