c# - 为什么代码不会死锁

标签 c# wpf mvvm locking task-parallel-library

有人可以向我解释为什么这段代码不会导致死锁吗?

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 的代码,但它不等待它完成

因此,一个可能的事件序列是这样的:

  1. StartAsync() 在后台线程上获取锁。
  2. 引发了 MyList
  3. PropertyChanged
  4. PropertyChanged 的处理程序调度在 UI 线程上访问 MyList 的代码。
  5. PropertyChanged 的处理程序返回。
  6. 锁被释放。
  7. UI 线程尝试访问 MyList
  8. UI 线程无需等待就获取锁,因为没有其他线程拥有它。

另一种表达方式:我认为您期望的是 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/

相关文章:

c# 为什么 "unsafe"超出应用程序地址范围

c# - ExecuteScalar 返回 null

c# - WPF Canvas 添加到背景

c# - 不使用 Microsoft.Win32 打开文件对话框

c# - 创建新实体时如何在加载时验证表单?

c# - 搜索 .NET Core 或标准 NuGet 包

c# - 调用另一个线程函数然后返回值

c# - 有项目时,SelectionChanged 中的 Items.Count = 0

c# - 从另一个类访问 mainwindow.xaml.cs 方法

c# - 这是使用命令模式的正确方法吗?