什么使实例成员线程不安全vs公共静态?

时间:2009-08-08 20:37:08

标签: c# .net thread-safety

所以我们都在MSDN上看到许多可用通用对象的线程通知:

“此类型的公共静态(在Visual Basic中为Shared)成员是线程安全的。不保证所有实例成员都是线程安全的。”

我的问题是,作为实例变量与公共静态相比,它是什么使它不安全?

5 个答案:

答案 0 :(得分:15)

这只是一般情况。

通常,静态方法是静态的,因为它们不依赖于它们,也不访问另一个线程也可以访问的任何实例定义的数据。通常,它们(静态方法)使用的唯一变量是声明的变量,并且绑定到实现该方法的类的静态内存,而不是分配给对象的内存 - (为该对象创建的类的实例) 。静态方法不能也不能引用或利用任何此类变量。如果方法使用这种实例数据变量,绑定到特定实例,则它不能是静态的。相反,Instance方法会访问实例的某些数据元素(属性或字段)。

如果,otoh,静态方法访问类的静态属性或字段,它同样是非线程安全的。

比赛可能需要四个条件。

  1. 第一个条件是存在可从多个线程访问的内存位置。通常,这些位置是全局/静态变量,或者是可从全局/静态变量访问的堆内存。
  2. 第二个条件是存在一个属性(通常称为不变量),它与这些共享内存位置相关联,这些位置必须为true或有效,才能使程序正常运行。通常,在更新发生更新之前,属性需要保持为正确。
  3. 第三个条件是在实际更新的某些部分期间不变属性不成立。 (在处理的某些部分,它暂时无效或错误)。
  4. 竞争发生必须发生的第四个也是最后一个条件是另一个线程在不变量被破坏时访问内存,从而导致行为不一致或不正确。

答案 1 :(得分:13)

没有内置使静态与实例差不多(重新线程安全),除了:

  • 静态方法通常是无状态的“纯函数”方法,使它们自动线程安全
  • 对静态成员有一个明确的期望线程安全的(因为你无法真正控制每个线程一次做什么) - 所以它是预期的 可以冒任何线程安全风险的静态方法是线程安全的

实例方法不是这样:

  • 实例方法通常访问该实例上的状态
  • 除非在文档
  • 中明确说明,否则不会期望线程安全

因此,通常情况下,调用者需要管理实例上的线程安全性。

有些例外情况是实例是线程安全的(通常用于与线程密切相关的事情,例如生产者 - 消费者队列) - 但IMO任何非线程安全的静态成员都是错误。

答案 2 :(得分:8)

这是国家的问题。一般使多线程不安全的方法是它们不以线程安全的方式访问共享状态。静态方法通常不访问共享状态,因此不太可能遇到此问题。如果静态/共享方法接触静态数据仍然可能存在竞争条件,但一般静态方法则不然。

答案 3 :(得分:0)

非线程安全方法的问题是对共享资源(如实例变量)的并发访问。如果静态方法对私有/本地数据起作用,则它本身就是线程安全的。但是,无法保证静态方法可以做到这一点 - 这必须明确地完成。

因此,对于静态方法是线程安全的,它不能在不使用同步的情况下访问静态成员,它应该在修改之前复制它接收的任何数据作为输入。

答案 4 :(得分:0)

TLDR; "这是否意味着静态方法本质上是线程安全的?答案是不。具有上述注释的类将具有线程安全的静态方法,因为Microsoft工程师以线程安全的方式编写代码,可能通过使用锁或其他线程同步机制" (引自http://odetocode.com/Articles/314.aspx

更多细节

这是什么?没什么,除了为那个特定类写的代码。

该语句是一个声明,告诉您编写该类的程序员已确保所有静态成员(方法和属性)都是线程安全的(但实例成员尚未这样做)。

已经确保静态是线程安全的,因为静态的,它们很可能会被多个线程调用,所以他们需要额外的工作以确保它没问题。静态方法通常也是无状态函数,这意味着它们通常已经是线程安全的(不需要额外的工作)。

相比之下,例如成员,声明就是他们告诉你他们没有那么小心。

通常,实例将由单个线程创建,并且只能由该线程访问;如果实例永远不会被多个线程访问,那么线程安全性就不是问题,所以程序员并不愿意添加它。

该声明不是关于静态vs实例的任何固有属性的声明;两者都可能不安全,除非你输入特定代码以确保多个线程可以毫无问题地访问它们(或者如果它们本质上已经是线程安全的,例如无状态函数)。

这只是一个声明,编写这些类的程序员已经确保静态成员是安全的,但对于实例成员却没有这样做。