C# 事件死锁
我明白了:C# 事件死锁,c#,C#,我明白了: object locker = new object(); // EDIT: sorry, omitted for simplicity. lock(this) is not the source of the problem. private Something property; public event SomethingHandler PropertyChanged; public Something Property { get { lock (l
object locker = new object(); // EDIT: sorry, omitted for simplicity. lock(this) is not the source of the problem.
private Something property;
public event SomethingHandler PropertyChanged;
public Something Property
{
get {
lock (locker) {
return property;
}
}
set {
lock (locker) {
property = value;
PropertyChanged();
}
}
}
然后这个:
MyClass.PropertyChanged += () =>
{
DoSomethingWithNewValue(MyClass.Property);
};
出于显而易见的原因,这会导致死锁。
处理这种情况的正确方法是什么
我可以将PropertyChanged()放在锁{}之后
或者从get{}中移除锁,或者将新值传递给处理程序,
但这一切看起来都有点不对劲。在锁定之后调度事件,否则永远无法保证事件处理代码(不受您控制)不会尝试读取属性并导致死锁,即使您锁定了私有对象。对我来说似乎不是显而易见的原因!
锁
根本帮不了你,因为副作用会在同一个线程上运行。您真的遇到了死锁还是堆栈溢出?DoSomethingWithNewValue
对MyClass.Property
做了什么?如果我理解正确,事件会在锁块内部引发,然后订阅该事件的代码尝试再次(通过getter)确认锁,导致锁永远等待。从getter中移除锁或将PropertyChanged()移到锁{}修复了它。@user3360080:因为您没有发布代码,这会重现问题,所以很难给您答案。发布真实代码。从引发事件的同一线程读取属性值不会导致死锁。OP代码示例没有告诉我们,该属性是从另一个线程读取的。我想我误解了锁的工作方式。从锁定块中调用的代码内部再次锁定可以吗?同一线程重新进入锁定也可以,因此通常这不应该是问题,但是如果事件处理程序中有其他同步代码,这种构造可能会导致非常微妙的错误。没有理由在锁里放零钱。我不会。@Gusdor:你检查过了吗?;)@斯彭德:不。我一直都是这样理解的。我认为这是一个很琐碎的知识,比如int32有多大,但唉,我错得太离谱了。我一直非常小心地避免再次进入。没有解释为什么这个例子会导致死锁。事件处理程序与初始锁位于同一线程上。