.NET多线程 - 我是否需要同步访问基本类型的变量?

时间:2009-08-11 10:14:22

标签: .net synchronization multithreading primitive-types

场景

我有一个带有bool Enabled属性的类,它被另一个线程上的循环用来查看它是否应该停止。我们的想法是,一个不同的线程可以将该属性设置为false,并阻止另一个线程干净地运行。

问题

我是否应该使用类似Enabled的内容序列化对lock (lockObject) { ... }属性的访问权限,或者是否安全?

9 个答案:

答案 0 :(得分:6)

原始类型读取是原子的,只要它们适合CPU读取。因此,32位原始类型读取在32位CPU上是原子的,而64位类型读取则不是。但是,除非它也是volatile,否则您的其他线程可能看不到由于缓存而发生的更改。

答案 1 :(得分:3)

我认为你只需要将布尔变量标记为volatile。这将确保您希望停止运行的线程始终看到此布尔值的最新值。

答案 2 :(得分:3)

如果一个线程读取该值而另一个线程写入该值,在这种情况下它是安全的,但要注意使用volatile关键字声明Enabled属性,以确保在运行时该值将同步到所有处理器使用双核PC。

答案 3 :(得分:3)

正如其他人已经正确陈述的那样,可以使用volatile(或变量上的lock)以线程安全的方式访问变量的值。

如果不生成变量volatile,编译器可能会应用优化技术来重新排序可能导致意外和不可预测结果的指令。

C#语言规范(10.4.3 Volatile fields)的相关部分进一步指出:

  

对于易失性字段,例如重新排序   优化受到限制:

     
      
  • 读取volatile字段称为volatile读取。不稳定   阅读有“获得语义”;那是,   它保证在任何之前发生   对之后发生的内存的引用   它在指令序列中。
  •   
  • 写入易失性字段称为易失性写入。不稳定   写有“释放语义”;那   是的,它保证会在之后发生   之前的任何记忆参考   在指令中写入指令   序列
  •   
     

这些限制确保了所有   线程将观察易失性写入   由任何其他线程执行   他们被执行的顺序。一个   符合实施不是   要求提供单一总额   可以看到易失性写入的排序   来自所有执行线程。该   volatile字段的类型必须是1   以下内容:

     
      
  • 参考类型。
  •   
  • 类型bytesbyteshortushortintuintchar,{{1 }}, 要么   float
  •   
  • bool - 类型的枚举基类型为byte,sbyte,short,ushort,   int或uint。
  •   

答案 4 :(得分:1)

如果你不使用volatile或锁定布尔值,它将工作x86。但它可能不适用于英特尔的Itanium CPU(IA64)。这里的a good codeproject kb article解释了这一切。

答案 5 :(得分:1)

如果你没有将它标记为volatile,那么它将在单CPU计算机上工作(因为32位原子性),但不能用于具有多个CPU的PC,因为它将保留其在管芯缓存中的值而不能检索到它最新价值,因此您需要使用Volatile进行标记。如果它的大小为32位,那么它就不需要锁定项目,因为它只是一个注册表大小的变化,因此是原子的。

这里有一篇文章:www.yoda.arachsys.com/csharp/threads/volatility.shtml

还有一种称为同步域的内容。

同步域以声明方式提供对对象的线程访问的自动同步。此类是作为支持.NET远程处理的基础结构的一部分引入的。希望表明类要对其对象进行同步访问的开发人员必须使该类继承自ContextBoundObject,并使用SynchronizationAttribute标记它,如下所示:

[Synchronization]
public class MyController : ContextBoundObject 
{
  /// All access to objects of this type will be intercepted
  /// and a check will be performed that no other threads
  /// are currently in this object's synchronization domain.
}

有关Syncronisation域的更多信息,请访问:msdn.microsoft.com/en-us/magazine/dd569749.aspx

答案 6 :(得分:0)

如果你担心丑陋的锁定,你可以在这种情况下使用Interlocked.Exchange

答案 7 :(得分:0)

有一个MSDN示例准确描述了您要执行的操作:How to: Create and Terminate Threads (C# Programming Guide)。它建议您将Enabled属性声明为volatile,而不需要lock

答案 8 :(得分:0)

您可以根据已编写的内容使用volatilelock标记变量。

然而,您正在尝试完成的任务(允许线程通过信令相互通信)已经构建到.NET框架中。

看看ManualResetEvent at MSDN