Trying to find and understand the best approach to implement a thread-safe number generator in .NET Core 2.x or higher
First Iv'e found this - https://web.archive.org/web/20160326010328/http://blogs.msdn.com/b/pfxteam/archive/2009/02/19/9434171.aspx
After reading through it seems to me like there are couple of "good" ways -
- ThreadStatic Random instance, with a global random instance to generate seeds
- ThreadStatic Random instance, with a global RNGCryptoServiceProvider to generate seeds
Where basically you choose the latter if a strong cryptographically random is a requirement.
After some additional research I found out that since .NET Core 2.x System.Random class was revised, therefore the default seed generation which is no longer primary dependent on the system timer. (https://blogs.siliconorchid.com/post/coding-inspiration/randomness-in-dotnet)
Question - How does this affect the implementation of a thread-safe random class?
Refrencing the first link Iv'e shared code solution -
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();
}
}
Since dotnet core 2.x adjustments is a global locked seed generator even required? or a basic ThreadStatic random instance is all thats needed? such as -
public static class ThreadSafeRandom
{
[ThreadStatic]
private static Random _local;
public static int Next()
{
Random inst = _local;
if (inst == null)
{
_local = inst = new Random();
}
return inst.Next();
}
}
CodePudding user response:
- The algorithm the
System.Randomclass use when instantiated with default constructor has changed to the new one, but the class is still not thread-safe, so old technique like using[ThreadStatic]is still needed. - In .NET Core, the default seed value is produced by the thread-static, pseudo-random number generator. That means you don't need to implement global seed generator anymore.
- Use
RandomNumberGeneratorwhen you really want to make sure your random number is secure. For example, if you just want to display random daily messages, useSystem.Random, but if you want to generate a random secret string, useRandomNumberGenerator.
CodePudding user response:
From .NET 6 you can use Random.Shared to get a thread-safe instance of Random.
The documents say this:
Provides a thread-safe Random instance that may be used concurrently from any thread.
https://docs.microsoft.com/en-us/dotnet/api/system.random.shared?view=net-6.0
There's no need to get fancy anymore.
To get a random integer you just need to do:
int number = Random.Shared.Next();
If you want cryptographically strong randomness, then Eric Lippert's BetterRandom is the way to go:
public static class BetterRandom
{
private static readonly ThreadLocal<System.Security.Cryptography.RandomNumberGenerator> crng = new ThreadLocal<System.Security.Cryptography.RandomNumberGenerator>(System.Security.Cryptography.RandomNumberGenerator.Create);
private static readonly ThreadLocal<byte[]> bytes = new ThreadLocal<byte[]>(() => new byte[sizeof(int)]);
public static int NextInt()
{
crng.Value.GetBytes(bytes.Value);
return BitConverter.ToInt32(bytes.Value, 0) & int.MaxValue;
}
public static double NextDouble()
{
while (true)
{
long x = NextInt() & 0x001FFFFF;
x <<= 31;
x |= (long)NextInt();
double n = x;
const double d = 1L << 52;
double q = n / d;
if (q != 1.0)
return q;
}
}
}
Start here to read more: https://ericlippert.com/2019/01/31/fixing-random-part-1/
