Initializing ThreadStatic field still causes NullReferenceException

我怕爱的太早我们不能终老 提交于 2019-11-27 11:57:44

问题


I've written myself a multi-threaded random generator

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

However, it throws me a NullReferenceException on firing Next(), which I don't understand. Is that kind of initializing ThreadStatic fields forbidden somehow?

I know I could just check if the field's initialized every time, but that's not the solution I'm looking for.


回答1:


Initializing ThreadStatic fields is a little tricky. In particular there is this caveat:

Do not specify initial values for fields marked with ThreadStaticAttribute, because such initialization occurs only once, when the class constructor executes, and therefore affects only one thread.

in the MSDN Docs. What this means is that the thread running when the class is initialized gets that initial value you've defined in the field declaration, but all other threads will have a value of null. I think this is why your code is exhibiting the undesirable behavior described in your question.

A fuller explanation is in this blog.

(a snippet from the blog)

[ThreadStatic]
private static string Foo = "the foo string";

The ThreadStatic is initialized in the static constructor - which only executes once. So only the very first thread is assigned "the foo string" when the static constructor executes. When accessed in all subsequent threads, Foo is left at the uninitalized null value.

The best way to work around this is to use a property to access the Foo prop.

[ThreadStatic]
private static string _foo;

public static string Foo {
   get {
     if (_foo == null) {
         _foo = "the foo string";
     }
     return _foo;
   }
}

Note that there is no need for a lock in the static property, because each thread is acting upon the _foo that is just for that thread. There can't be contention with other threads. This is covered in this question: ThreadStatic and Synchronization




回答2:


Previous answer is correct as to the reason for the issue.

if you can use .NET 4 or higher, use ThreadLocal instead as is built with an initializer.

See ThreadStatic v.s. ThreadLocal<T>: is generic better than attribute?

Then you don't need the accessor overload or null check on every read.



来源:https://stackoverflow.com/questions/18086235/initializing-threadstatic-field-still-causes-nullreferenceexception

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!