我需要在C#.Net中创建一个Thread安全的静态变量

时间:2009-08-10 13:01:56

标签: c# static thread-safety

好吧,它比问题复杂一点。

class A
{
   static int needsToBeThreadSafe = 0;

   public static void M1()
   {
     needsToBeThreadSafe = RandomNumber();
   }

   public static void M2()
   {
     print(needsToBeThreadSafe);
   }
}

现在我要求在M1()和M2()之间调用'needsToBeThreadSafe'保持线程安全。

7 个答案:

答案 0 :(得分:21)

如何:

public static void M1()
{
    Interlocked.Exchange( ref needsToBeThreadSafe, RandomNumber() );
}

public static void M2()
{
    print( Interlocked.Read( ref needsToBeThreadSafe ) );
}

答案 1 :(得分:19)

您可能要问的是[ ThreadStatic ]属性。如果您希望使用 A 类的每个线程都有自己独立的 needsToBeThreadSafe 值,那么您只需要使用[ ThreadStatic ]属性。

有关详细信息,请参阅MSDN documentation for ThreadStaticAttribute

答案 2 :(得分:8)

您有两种选择:给出您提供的代码最简单的是volatile关键字。将needsToBeThreadSafe声明为static volatile int,这将保证引用该变量的任何线程都将获得“最新”副本,并且该变量不会缓存在您的代码中。

话虽如此,如果你想更一般地确保M1()M2()“原子地”执行(或者至少完全相互执行),那么你想要使用{{1} }。最干净的语法是使用“锁定块”,如下所示:

lock

至于采取哪种方法,这取决于你,应该由代码决定。如果你只需要确保成员赋值传播到所有线程而不是缓存,那么private static object locker = new Object(); //.. public static void M1() { lock(locker) { //..method body here } } public static void M2() { lock(locker) { //..method body here } } 关键字就更简单了,并且可以很好地完成工作。如果超出此范围,您可能需要使用volatile

答案 3 :(得分:4)

class A
{
   static int needsToBeThreadSafe = 0;
   static object statObjLocker = new object();

   public static void M1()
   {
       lock(statObjLocker)
       {
          needsToBeThreadSafe = RandomNumber();
       }
   }

   public static void M2()
   {
       lock(statObjLocker)
       {
          print(needsToBeThreadSafe);
       }
   }
}

答案 4 :(得分:2)

听起来你需要Volatile成员。

static volatile int needsToBeThreadSafe = 0;

答案 5 :(得分:2)

您还可以使用ReaderWriterLockSlim,这对于多次读取和更少写入更有效:

static int needsToBeThreadSafe = 0;
static System.Threading.ReaderWriterLockSlim rwl = new System.Threading.ReaderWriterLockSlim();

public static void M1()
{
    try
    {
        rwl.EnterWriteLock();
        needsToBeThreadSafe = RandomNumber();
    }
    finally
    {
        rwl.ExitWriteLock();
    }

}

public static void M2()
{
    try
    {
        rwl.EnterReadLock();
        print(needsToBeThreadSafe);
    }
    finally
    {
        rwl.ExitReadLock();
    }
}

答案 6 :(得分:2)

首先,我同意使用lock()的答案,这是最安全的方式。

但是存在一种更简约的方法,您的示例代码仅显示使用needsToBeThreadSafe的单个语句,并且因为 int 是原子的,您只需要阻止编译器使用缓存易失性:

class A
{
   static volatile int needsToBeThreadSafe = 0;

}

但如果你需要在多个语句中使用toTeTereadSafe作为'ThreadSafe',请使用锁。