2010-06-29 82 views
10

在许多MSDN文档中,这是写在线程安全标题下;msdn:什么是“线程安全”?

“此类型的任何公共静态(Visual Basic中的Shared)成员都是线程安全的,但不保证所有实例成员都是线程安全的。例如

; here

有人可以用一个相当简单的方式解释它吗? 谢谢:)

回答

11

Eric Lippert在这方面有出色的blog post。基本上它本身就没有什么意义。

就我个人而言,当我看到锅炉板时,我不太相信MSDN。这并不总是意味着它所说的。例如,它说的是关于Encoding的同样的事情 - 尽管我们都使用遍布整个地方的多个线程的编码。

除非我有任何理由相信否则(我使用Encoding)我认为我可以从任何线程中调用任何静态成员而不会损坏全局状态。如果我想使用实例来自不同线程的同一对象的成员,我假设没关系,如果我确保 - 通过锁定 - 一次只有一个线程将使用该对象。 (这是情况并非总是如此,当然,有些对象有线程关联积极不喜欢从多个线程中使用,即使在地方锁定。UI控件都是明显的例子。)

当然,它变得非常棘手如果对象被共享不明显 - 如果我有两个对象共享一个对第三个对象的引用,那么我可能最终使用独立于不同线程的前两个对象,并具有所有适当的锁定 - 但仍然最终会损坏第三个对象。

如果一个类型确实宣传自己是线程安全的,我希望它会提供一些关于它的细节。如果它是不可变的,这很容易 - 你可以使用实例,但不需要担心它们。它是部分或全部“线程安全”的类型,在细节非常重要的情况下是可变的。

+3

MS的小记录意味着什么,“我们没有在实例方法中做太多/任何锁定[可能出于性能的原因],所以如果你去了,并且在它上面打了十几个线程,不要为我们哭泣,这不是一个错误,我们警告过你。“ – cHao 2010-06-29 05:22:53

+1

@cHao:获取多线程权限比实例方法锁定要多得多。你经常想让一系列的方法调用以原子方式工作 - 在这种情况下,内部锁定量不会有帮助。遍历集合是一个明显的例子。 – 2010-06-29 05:24:46

+0

@Jon:同意,还有更多。但是MS没有什么可以期待的,因为跨多个方法调用的内置原子对任何重视稳定性的人都没有意义。 (它需要API文档来说明诸如“如果你调用IsEmpty()并且它返回false,你必须调用Remove()或者ReleaseLock()来避免死锁”)。即使在单一方法中,它也可能导致性能问题,如果它被不必要地使用。所以MS理所当然地不打扰。这是我的观点。 – cHao 2010-06-29 06:58:32

5

您可以同时从多个线程访问该类的任何公共静态成员,而不会中断该类的状态。如果多个线程尝试使用实例方法(同时未标记为“静态”的那些方法)访问对象,则该对象可能会损坏。

如果尝试从多个线程同时访问同一个类的实例,则该类是“线程安全的”而不是会导致问题。

4

“线程安全”的对象意味着如果两个线程在同一时间(或在单CPU系统上非常接近的时间)使用它,那么就不存在被该访问破坏的机会。这通常是通过获取和释放可能导致瓶颈的锁来实现的,因此,“线程安全”如果在不需要的时候完成,也可能意味着“慢”。

公共静态成员非常期望在线程之间共享(请注意,VB甚至调用它“共享”),所以公共静态一般是以可以安全使用的方式制作的。

实例成员通常不是线程安全的,因为在一般情况下它会减慢速度。如果你有一个你想在线程之间共享的对象,那么你需要做自己的同步/锁定。

0

要理解这一点,请考虑以下示例。 在.net class HashSet的MSDN描述中,有一部分讲述了线程的安全性。在HashSet类的情况下,MSDN表示“此类型的任何公共静态(Visual Basic中的共享)成员都是线程安全的。任何实例成员不保证是线程安全的。“ 因为我们都知道竞争条件和僵局的概念,但微软想用简单的英语说什么? 如果两个线程将两个值添加到HashSet的“实例”中,则会出现一些情况,我们可以将其计为一个。因为我们现在在HashSet中有两个对象,所以在这种情况下HashSet对象被损坏,但它的计数只显示一个。但是,即使两个线程同时添加值,HashSet的公共静态版本也不会面临这种损坏。