Skip to main content
 首页 » 编程设计

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

2024年01月28日34del

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

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 线程无需等待就获取锁,因为没有其他线程拥有它。
  9. …

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