初始化ThreadStatic字段仍会导致NullReferenceException

Tar*_*rec 37 c# random thread-safety threadstatic

我自己写了一个多线程随机生成器

public static class MyRandGen
{
    private static Random GlobalRandom = new Random();
    [ThreadStatic]
    private static Random ThreadRandom = new Random(SeedInitializer());
    private static int SeedInitializer()
    {
        lock (GlobalRandom) return GlobalRandom.Next();
    }

    public static int Next()
    {
        return ThreadRandom.Next();
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,它在抛出Next()时抛出了NullReferenceException,我不明白.这种初始化ThreadStatic字段是否被禁止?

我知道我可以检查每次都是否已初始化该字段,但这不是我正在寻找的解决方案.

hat*_*ica 61

初始化ThreadStatic字段有点棘手.特别是有一点需要注意:

不要为标记有ThreadStaticAttribute的字段指定初始值,因为这样的初始化只在类构造函数执行时发生一次,因此只影响一个线程.

MSDN文档中.这意味着初始化类时运行的线程获取您在字段声明中定义的初始值,但所有其他线程的值都为null.我认为这就是为什么您的代码表现出您的问题中描述的不良行为的原因.

更全面的解释是在这篇博客中.

(来自博客的片段)

[ThreadStatic]
private static string Foo = "the foo string";
Run Code Online (Sandbox Code Playgroud)

ThreadStatic在静态构造函数中初始化 - 它只执行一次.因此,当静态构造函数执行时,只有第一个线程被赋予"foo字符串".在所有后续线程中访问时,Foo保留在未初始化的空值.

解决此问题的最佳方法是使用属性访问Foo prop.

[ThreadStatic]
private static string _foo;

public static string Foo {
   get {
     if (_foo == null) {
         _foo = "the foo string";
     }
     return _foo;
   }
}
Run Code Online (Sandbox Code Playgroud)

请注意,静态属性中不需要锁定,因为每个线程都只_foo对该线程执行操作.其他线程无法争用.这个问题包含在这个问题中:ThreadStatic和Synchronization

  • @cost - 当然,两个不同的线程可以同时击中吸气剂.但是每个线程都在访问它自己的`_foo`,它只存在于那个线程(这就是ThreadStatic所做的),所以没有必要锁定以防止它们踩到`_foo`.他们没有访问相同的`_foo`.http://stackoverflow.com/questions/11507881/threadstatic-and-synchronization.至于来自同一线程的两个不同的程序流...我不知道同一线程内多个程序流之间的上下文切换的特征. (3认同)
  • @cost - 一个线程不能被自己打断.只要GUI线程在getter中,GUI线程中的Windows计时器就会被阻塞.我知道单个线程在退出第一个之前第二次进入getter的唯一方法就是如果你故意通过在getter中放入一个DoEvents调用或者将getter写为递归来实现它.即使在那些情况下,锁定也无济于事.锁只会阻止其他线程.单个线程可以在同一对象上获得多个锁,而不会阻塞自身.这允许它们用于重入代码. (3认同)
  • @cost - 每个线程都有自己的`_foo`,同一个线程不能同时多次访问getter.请参阅http://stackoverflow.com/questions/1087599/is-this-a-thread-safe-way-to-initialize-a-threadstatic.此外,MSFT说"这种类型的任何公共静态成员都是线程安全的"http://msdn.microsoft.com/en-us/library/system.threadstaticattribute(v=vs.110).aspx (2认同)