有人可以向我解释为什么这段代码不会导致死锁吗?
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 绑定(bind)到 WPF UI 上的 Datagrid。
_myObjects 只是对象的随机列表。
是不是因为 OnPropertyChange 只是通知 UI 它必须从 MyList 获取新数据并且只是返回而不关心 UI 是否实际获取数据?
我知道OnPropertyChanged 在单独的线程上调用,但 UI 存在于单个线程上(不是 O.o),因此获得通知的线程也是获取数据的线程。我会认为锁不会因此而无法释放吗?
最佳答案
这里的关键实现是 PropertyChanged
的处理程序确实在 UI 线程上安排了一些访问 MyList
的代码,但它不等待它完成。
因此,一个可能的事件序列是这样的:
StartAsync()
在后台线程上获取锁。
引发了 PropertyChanged
。PropertyChanged
的处理程序调度在 UI 线程上访问MyList
的代码。PropertyChanged
的处理程序返回。- 锁被释放。
- UI 线程尝试访问
MyList
。 - UI 线程无需等待就获取锁,因为没有其他线程拥有它。
- …
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
}
});
关于c# - 为什么代码不会死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15650778/