2009-08-10 52 views
12

好的,它比问题稍微复杂一些。我需要在C#中创建一个线程安全的静态变量.Net

class A 
{ 
    static int needsToBeThreadSafe = 0; 

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

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

现在我需要M1()和M2()之间调用 'needsToBeThreadSafe' 住宿线程安全的。

+1

你的意思是你想M1()和M2()调用是原子? – Bombe 2009-08-10 13:04:04

+2

“保持线程安全”是什么意思? – 2009-08-10 13:04:27

回答

18

什么,你可能会试图询问是[ThreadStatic]属性。如果你想使用类A拥有的needsToBeThreadSafe自己独立的价值每一个线程,那么你只需要装饰的那场与[ThreadStatic]属性。

欲了解更多信息,请参考MSDN documentation for ThreadStaticAttribute

+0

我想其他人也是对的,但对于我的情况这完美的作品。 – Storm 2009-08-10 13:56:51

+5

好的,但ThreadStatic不是ThreadSafe。 – 2009-08-10 14:02:14

+0

不知何故,我只是意识到他真正追求的是线程之间不共享的值。此外,ThreadStatic **是**线程安全的,因为实际上没有两个线程访问同一个变量(即使它看起来像它们一样)。 – paracycle 2009-08-10 14:53:32

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); 
     } 
    } 
} 
+0

statObjLocker应该* readonly *,只是预防措施... – ipavlu 2015-11-14 23:49:05

8

您有两种选择:最简单的给出的代码是volatile关键字。声明needsToBeThreadSafestatic volatile int,这将保证任何引用该变量的线程都将获得“最新”副本,并且该变量不会被缓存在您的代码中。这就是说,如果你想更一般地确保M1()M2()执行“原子”(或至少是彼此独占),那么你想要使用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会更简单,并且可以很好地完成这项工作。如果超出这个范围,您可能需要使用lock

+0

更衣室应*只读*,只是预防措施... – ipavlu 2015-11-14 23:49:18

2

听起来像你需要一个Volatile成员。

static volatile int needsToBeThreadSafe = 0; 
+0

这是2009年的评论,但现在最好避免波动,因为它有副作用... – ipavlu 2015-11-14 23:50:27

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(); 
    } 
} 
+0

rwl应该* readonly *,只是预防措施... – ipavlu 2015-11-14 23:51:02

2

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

但存在一个更简约的方式,你的示例代码仅显示了needsToBeThreadSafe,自int是原子,你只需要使用挥发性的,以防止编译器缓存单个语句:

class A 
{ 
    static volatile int needsToBeThreadSafe = 0; 

} 

但是,如果你需要needsToThreadSafe作为多线程的'ThreadSafe',使用锁。

+0

这是2009年的答案,但现在,它会更好地使用回答建议的锁比易变易挥发有副作用,往往容易造成问题... – ipavlu 2015-11-14 23:52:41

20

如何:

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

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

我喜欢这一个,是安全的,速度超快,SHAME它在五年后只有4个upvotes(包括我的)! – ipavlu 2015-11-14 23:53:57