一次又一次我发现自己必须编写BindingList和ObservableCollection的线程安全版本,因为当绑定到UI时,这些控件不能从多个线程中更改。我试图理解的是为什么这种情况 - 是设计错误还是这种行为是故意的?为什么像BindingList或ObservableCollection这样的类不是线程安全的?
回答
问题在于设计一个线程安全的集合并不简单。当然,设计一个可以在不损坏状态的情况下可以从多个线程修改/读取的集合足够简单。但是设计一个可用的集合要困难得多,因为它是从多个线程更新的。以下面的代码为例。
if (myCollection.Count > 0) {
var x = myCollection[0];
}
假设myCollection是一个线程安全的集合,其中保证添加和更新不会损坏状态。此代码不是线程安全的并且是竞争条件。
为什么?即使myCollection是安全的,但不保证在对myCollection的两个方法调用之间不会发生更改:namedly Count和索引器。另一个线程可以进入并删除这些调用之间的所有元素。
这种类型的问题使得使用这种类型的集合非常坦率地说是一场噩梦。您不能让一个调用的返回值影响集合的后续调用。
编辑
我扩大在最近的一篇博客讨论:http://blogs.msdn.com/jaredpar/archive/2009/02/11/why-are-thread-safe-collections-so-hard.aspx
要一点点添加到Jared的出色答卷:线程安全没有免费的午餐。许多(大多数?)集合仅用于单个线程中。为什么这些集合有性能或功能的处罚来应对多线程的情况?
如果您想要发疯 - here's a ThreadedBindingList<T>
会自动在UI线程上执行通知。但是,对于一个线程一次进行更新等,它仍然是安全的。
从所有其他的答案收集的想法,我认为这是解决问题的最简单的方法:
变化从你的问题:“为什么不是X类理智”
到
“什么是类X这样的理智呢?”
在类的构造函数,在创建 你的观察集合获取当前displatcher。因为你指出,修改需要在原始线程上完成 ,这个线程可能不是主要的的GUI线程。 所以App.Current。调度员不是alwasys的权利, 并不是所有的类都有this.Dispatcher。
_dispatcher = System.Windows.Threading.Dispatcher.CurrentDispatcher; _data = new ObservableCollection<MyDataItemClass>();
使用调度程序来调用您的代码段 需要原来的线程。
_dispatcher.Invoke(new Action(() => { _data.Add(dataItem); }));
这应该为你做的伎俩。虽然有些情况下您可能更喜欢.BeginInvoke而不是。启动。
- 1. jpeg_write_scanlines和glTexImage2D线程安全。为什么不这样崩溃?
- 2. 为什么这个线程是不是安全
- 3. “这个方法不是线程安全的”是什么意思?
- 4. 为什么心不是这个计数器类“线程安全的”
- 5. 这些类是线程安全的吗?
- 6. 为什么这段代码是可重入的,但不是线程安全的
- 7. 这为什么不安全?
- 8. 为什么我的代码不是线程安全的?
- 9. 为什么std :: queue :: empty()不是线程安全的?不应该const函数是线程安全的?
- 10. 什么是线程安全的对象
- 11. 为什么静态类和单例模式类不是线程安全的?
- 12. 为什么OSX文件atoi/atof不是线程安全的?
- 13. 为什么阅读不是线程安全的?
- 14. 为什么JPA EntityManager根据定义不是线程安全的?
- 15. 为什么此代码不是线程安全的?
- 16. 为什么不可变对象是线程安全的?
- 17. 这个类是否线程安全?
- 18. 这个类是不是线程安全的?
- 19. “StringBuffer是同步的(或线程安全的)并且StringBuilder不是”,为什么这会使StringBuffer方法变慢?
- 20. NSMutableDictionary不是线程安全的:那么?
- 21. EF上下文不是线程安全的,为什么不通过设计使线程安全?
- 22. 是C#6吗? (猫王op)线程安全吗?如果是这样,怎么样?
- 23. 你是什么意思Ruby on Rails不是线程安全的?
- 24. 线程安全是什么意思?
- 25. 线程安全是什么意思?
- 26. msdn:什么是“线程安全”?
- 27. 为什么这被认为是Sharepoint中的“不安全更新”?
- 28. 为什么我在这里没有安全或不安全的操作?
- 29. 为什么添加了非线程安全的java类?
- 30. 为什么maxConcurrentSessions默认为这样一个低值?什么是安全价值?
我有完全相同的问题。我如何使用Dispatcher或者从后台线程添加项目到我的BindingList? – Houman 2010-08-27 17:58:07
是的,简而言之,.NET集合*接口*本身的设计不适合线程安全。正如Jared指出的那样,Count属性在多线程环境中是无用的。 – 2011-01-17 03:29:02
`IList`功能有很多有用的子集,可以用线程安全的方式实现。移除东西或移动东西的项目会产生问题,但接口的其余部分对许多应用程序来说都是有用的子集。报告添加项目索引的“Add”版本将会很有帮助,但并非所有的应用程序都需要它。如果添加的每个项目在列表的生命周期中将继续存在于同一个插槽中,则线程安全的IList实现在很多多线程场景中可能非常有用,而无需外部锁定。 –
supercat
2013-05-23 19:00:41