2014-02-12 46 views
0

我有一个属性与支持领域,我想使线程安全(获取和设置)。 get和set方法除了设置和返回之外没有任何逻辑。属性与挥发或锁

我认为有两种方法来封装属性self(volatile和lock)中的逻辑。 我对这两个人的理解是正确的还是我犯了错误?

下面是我的例子:

public class ThreadSafeClass 
    { 
     // 1. Volatile Example: 

     private volatile int _processState_1; 
     public int ProcessState_1 
     { 
      get { return _processState_1; } 
      set { _processState_1 = value; } 
     } 

     // 2. Locking Example: 

     private readonly object _processState_2Lock = new object(); 
     private int _processState_2; 
     public int ProcessState_2 
     { 
      get 
      { 
       lock (_processState_2Lock) 
       { 
        return _processState_2; 
       } 
      } 
      set 
      { 
       lock (_processState_2Lock) 
       { 
        _processState_2 = value; 
       } 
      } 
     } 
    } 
+4

你的理解当然似乎是错误的(或至少是不完整的),但很难提供具体的答案,因为这只是一堆代码。你没有提到你的理解究竟是什么*。另外请注意,“线程安全”没有单一的定义,所以它也不清楚你自己的定义是什么。 – Jon

回答

1

如需更多信息,请参阅great site by J. Albahari

同步结构可分为四类:

单纯堵塞的方法:

这些等待另一个线程完成或一段时间过去。 Sleep,JoinTask.Wait是简单的阻塞方法。

锁定构造:

这些限制可以执行某些活动或在一个时间执行的代码段的线程的数目。独占锁定结构是最常见的 - 它们一次只允许一个线程,并允许竞争线程访问常见数据而不会相互干扰。标准独占锁定构建体是lockMonitor.Enter/Monitor.Exit),MutexSpinLock。非唯一的locking构造是Semaphore,SemaphoreSlimreader/writer锁。

信令构建体:

这些允许线程暂停,直到接收到来自另一个的通知时,避免了低效率的轮询的需要。有两种常用的信号设备:事件等待句柄和监视器的等待/脉冲方法。 Framework 4.0引入了CountdownEventBarrier类。

无阻塞同步结构:由呼吁处理器的原语

这些保护访问公共字段。 CLR和C#提供以下非阻断结构:Thread.MemoryBarrier,Thread.VolatileRead,Thread.VolatileWrite,volatile关键字和Interlocked类。


volatile关键字:

volatile关键字指示编译器生成在每次从该字段读取的获取围栏,并在每一个释放围栏写入该字段。获取栅栏可防止在栅栏之前移动其他读取/写入;释放栅栏可防止在栅栏后移动其他读取/写入。这些“半边栅栏”比全栅栏更快,因为它们为运行时间和硬件提供了更多的优化空间。

碰巧,英特尔的X86和X64处理器总是适用获取栅栏,以读取和释放栅栏来写 - 无论是否使用volatile关键字 - 所以这个关键字在硬件上没有任何影响,如果你”重新使用这些处理器。但是,volatile确实对编译器和CLR以及64位AMD和(更大程度上)Itanium处理器执行的优化有影响。这意味着你不能因为你的客户运行特定类型的CPU而放松。

First instruction Second instruction Can they be swapped? 
Read    Read    No 
Read    Write    No 
Write    Write    No (The CLR ensures that write-write operations are never swapped, even without the volatile keyword) 
Write    Read    Yes! 

注意,将挥发性并不妨碍写入,然后被交换的读取,这样就可以创建脑筋急转弯:

将挥发至字段的作用可以概括如下。 Joe Duffy用下面的例子很好地说明了这个问题:如果Test1Test2在不同的线程上同时运行,a和b都可能以0值结束(尽管在xy上都使用了volatile):

class IfYouThinkYouUnderstandVolatile 
{ 
    volatile int x, y; 

    void Test1()  // Executed on one thread 
    { 
    x = 1;   // Volatile write (release-fence) 
    int a = y;  // Volatile read (acquire-fence) 
    ... 
    } 

    void Test2()  // Executed on another thread 
    { 
    y = 1;   // Volatile write (release-fence) 
    int b = x;  // Volatile read (acquire-fence) 
    ... 
    } 
} 

MSDN文档在使用挥发性关键字确保了最先进的最新值是存在于在所有时间字段。这是不正确的,因为正如我们所看到的,可以重新编写随后的读取。

这提供了避免volatile的强大案例:即使您了解本示例中的微妙之处,其他开发您的代码的开发人员是否也会理解它? Test1Test2(或锁)中两个作业中的每个作业之间的完整栅栏解决了这个问题。

volatile关键字不支持传递引用参数或捕获的局部变量:在这些情况下,您必须使用VolatileReadVolatileWrite方法。