有些人可以向我解释为什么这段代码不会导致死锁?
static Object listlock = new Object();
void StartAsync()
{
System.Threading.Tasks.Task.Factory.StartNew(() =>
{
lock(listlock)
base.OnPropertyChanged("MyList");
});
}
public ObservableCollection<MyObjects> MyList
{
get
{
lock(listlock)
return new ObservableCollection<MyObjects>(_myObjectList);
}
}
一些背景细节:
该程序使用 MVVM 模式, MyList 绑定到 WPF用户界面上的数据网格。
_myObjects 只是一个随机的对象列表。
是因为 OnPropertyChange 只是通知用户界面它必须从MyList获取新数据并且只是返回而不关心UI是否实际获得数据?是的我知道OnPropertyChanged在一个单独的线程上调用,但是UI存在于一个线程上(不是它),因此获得通知的线程也是获取数据的线程。我会认为锁定因为那个而无法释放?
答案 0 :(得分:3)
对于单锁上发生的死锁,你需要2个线程,这样第一个线程抓住锁并等待让第二个线程获取同一个锁。否则你不会遇到死锁(即没有等待 lock
语句中的其他线程,或者只涉及一个线程。)
未来读者注意 - 以下不是WPF案例中的情况 - 请参阅svick的回答。在同一个线程上只有2个锁没有死锁的通用示例:
一种可能的情况是OnPropertyChanged的监听器调用MyList
以响应同一线程上的同步通知(在调用MyList
时检出调用堆栈)。在这种情况下,嵌套的lock
什么都不做,因为请求锁的线程已经拥有它。
答案 1 :(得分:3)
这里的关键实现是PropertyChanged
的处理程序确实安排了一些在UI线程上访问MyList
的代码,但不等待它完成。
所以,一个可能的事件序列是:
StartAsync()
获取后台线程的锁定。PropertyChanged
MyList
被提出。
PropertyChanged
的处理程序调度访问UI线程上的MyList
的代码。PropertyChanged
的处理程序返回。MyList
。另一种表达方式:我认为你期望的是PropertyChanged
的处理程序是这样的:
Dispatcher.Invoke(() =>
{
if (e.PropertyName == "MyList")
{
var newList = model.MyList;
// set newList as the current value of some binding
}
});
但事实上,它确实有类似的东西(唯一的区别是第一行):
Dispatcher.BeginInvoke(() =>
{
if (e.PropertyName == "MyList")
{
var newList = model.MyList;
// set newList as the current value of some binding
}
});