c# random thread-safety threadstatic

c# - La inicialización del campo ThreadStatic aún causa NullReferenceException



random thread-safety (1)

Me he escrito un generador aleatorio de subprocesos múltiples

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

Sin embargo, me lanza una NullReferenceException al disparar Next (), que no entiendo. ¿Es ese tipo de inicialización de campos ThreadStatic prohibido de alguna manera?

Sé que podría verificar si el campo se inicializó todas las veces, pero esa no es la solución que estoy buscando.


Inicializar los campos ThreadStatic es un poco complicado. En particular, hay esta advertencia:

No especifique los valores iniciales para los campos marcados con ThreadStaticAttribute, ya que dicha inicialización solo se produce una vez, cuando el constructor de la clase se ejecuta y, por lo tanto, afecta solo a un hilo.

en los documentos de MSDN . Lo que esto significa es que el subproceso que se ejecuta cuando se inicializa la clase obtiene ese valor inicial que ha definido en la declaración de campo, pero todos los demás subprocesos tendrán un valor de nulo. Creo que esta es la razón por la cual su código exhibe el comportamiento indeseable descrito en su pregunta.

Una explicación más completa es en este blog .

(un fragmento del blog)

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

ThreadStatic se inicializa en el constructor estático, que solo se ejecuta una vez. Por lo tanto, solo al primer hilo se le asigna "la cadena foo" cuando se ejecuta el constructor estático. Cuando se accede a todos los subprocesos posteriores, Foo queda en el valor nulo no inicializado.

La mejor manera de evitar esto es usar una propiedad para acceder al accesorio Foo.

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

Tenga en cuenta que no hay necesidad de un bloqueo en la propiedad estática, porque cada hilo está actuando sobre el _foo que es solo para ese hilo. No puede haber contención con otros hilos. Esto se trata en esta pregunta: ThreadStatic y sincronización