7

Here is a nice article describing thread safety of random numbers:Getting random numbers in a thread-safe way

But I'm stuck with the "RandomGen2" example:

public static class RandomGen2 
{ 
    private static Random _global = new Random(); 
    [ThreadStatic] 
    private static Random _local;

    public static int Next() 
    { 
       Random inst = _local; 
       if (inst == null) 
       { 
           int seed; 
           lock (_global) seed = _global.Next(); 
           _local = inst = new Random(seed); 
       } 
       return inst.Next(); 
   } 

}

Why is the thread static field copied to local variable: Random inst = _local; ? Why not to simply use

if (_local == null) .... return _local.Next()

zx81
  • 41,100
  • 9
  • 89
  • 105
Alexey Bychkov
  • 581
  • 5
  • 9
  • 2
    Important note, you can get [weird side effects](http://stackoverflow.com/questions/25390301/net-framework-random-number-generator-produces-repeating-pattern) when you chain random number generators like this. – Scott Chamberlain Aug 22 '14 at 13:28
  • You can find a documentation about this here https://devblogs.microsoft.com/pfxteam/getting-random-numbers-in-a-thread-safe-way/ – Flimtix Nov 05 '21 at 13:16

2 Answers2

12

Note: since writing this answer, I've become aware of issues creating multiple Random instances, even though it sounds like it should work. I've generally found that a better alternative is to have a single Random instance and just lock on that. Although that is a single potential bottleneck, in most applications it won't cause problems.


I suspect it's just to avoid the cost of reading the thread-static variable multiple times. It's relatively inefficient to do so, compared with reading a local variable.

Your suggestion would work, but it would be slightly less efficient, that's all. In other cases, there would be the possibility of the value changing between fetches - but of course that's not a problem in this case, as it's a thread-local variable.

With .NET 4 and higher, this would be simpler using ThreadLocal<T>:

public static class RandomGen2 
{ 
    private static Random _global = new Random(); 
    private static ThreadLocal<Random> _local = new ThreadLocal<Random>(() =>
    {
        int seed;
        lock (_global) seed = _global.Next();
        return new Random(seed);
    });


    public static int Next() 
    { 
        return _local.Value.Next();
    } 
}
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Which one is the most performant (if there is a difference) ? ThreadLocal or [ThreadStatic] ? – krimog Aug 22 '14 at 14:39
  • @krimog: I *think* `ThreadLocal` performs better, but you'd have to test to be sure. It may be dependent on architecture, too. – Jon Skeet Aug 22 '14 at 14:51
  • 1
    So, I did the test (i5 on a 32 bits OS with fwk 4.0). The two methods seem to have very similar performances with a small (on avg, < 5%) advantage for [ThreadStatic]. – krimog Aug 22 '14 at 15:23
  • There is a good example and explanation in the official docs: [The System.Random class and thread safety](https://learn.microsoft.com/en-us/dotnet/api/system.random#the-systemrandom-class-and-thread-safety) – axmrnv Mar 21 '18 at 13:39
  • A similar version to this answer was packaged as a [NuGet package](https://www.nuget.org/packages/ThreadSafeRandomizer) with source available on [GitHub](https://github.com/MarkCiliaVincenti/ThreadSafeRandomizer). – Mark Cilia Vincenti Mar 14 '22 at 08:49
4

Starting from .NET6, there is thread-safe Random out of the box:

var rndIntValue = Random.Shared.Next();

See details

Evgeny
  • 791
  • 7
  • 15