当前位置:  开发笔记 > 编程语言 > 正文

为什么BindingList或ObservableCollection这样的类不是线程安全的?

如何解决《为什么BindingList或ObservableCollection这样的类不是线程安全的?》经验,为你挑选了3个好方法。

一次又一次我发现自己必须编写BindingList和ObservableCollection的线程安全版本,因为当绑定到UI时,不能从多个线程更改这些控件.我想要了解的是为什么会出现这种情况 - 是设计错误还是故意这种行为?



1> JaredPar..:

问题是设计线程安全集合并不简单.当然,设计一个可以从多个线程修改/读取而不会破坏状态的集合非常简单.但是设计一个可用的集合要困难得多,因为它是从多个线程更新的.以下面的代码为例.

if ( myCollection.Count > 0 ) {
  var x = myCollection[0];
}

假设myCollection是一个线程安全的集合,其中保证添加和更新不会破坏状态.此代码不是线程安全的,并且是竞争条件.

为什么?即使myCollection是安全的,也不能保证在对myCollection的两个方法调用之间不会发生更改:命名为Count和索引器.另一个线程可以进入并删除这些调用之间的所有元素.

这种类型的问题使得使用这种类型的集合坦率地说是一场噩梦.您不能让一个调用的返回值影响对集合的后续调用.

编辑

我在最近的博客文章中扩展了这个讨论:http://blogs.msdn.com/jaredpar/archive/2009/02/11/why-are-thread-safe-collections-so-hard.aspx



2> Jon Skeet..:

为Jared的优秀答案添加一点:线程安全不是免费的.许多(大多数?)集合仅在单个线程中使用.为什么这些集合会有性能或功能处罚来应对多线程案例?



3> Jesse Chisho..:

从所有其他答案中收集想法,我认为这是解决问题的最简单方法:

更改您的问题:

"为什么X级不健全?"

"用X级这样做的理智是什么?"

    在类的构造函数中,在创建可观察集合时获取当前的置换器.正如您所指出的那样,需要在原始线程上进行修改,原始线程可能不是主要的 GUI线程.所以App.Current.Dispatcher并不是alwasys,并非所有类都有this.Dispatcher.

    _dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher;
    _data = new ObservableCollection();
    

    使用调度程序调用需要原始线程的代码段.

    _dispatcher.Invoke(new Action(() => { _data.Add(dataItem); }));
    

这应该为你做的伎俩.虽然有些情况你可能更喜欢.BeginInvoke而不是.Invoke.

推荐阅读
Gbom2402851125
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有