PROWAREtech
.NET: The Random Class is Not Thread-safe!
How to use the Random class in a thread-safe manner to find reliable random values.
How not to use the Random
class:
// This seems like it would work, but can generate duplicate sequences
Parallel.For(0, 10, i =>
{
var localRandom = new Random(); // BAD! Could get same seed in different threads
var number = localRandom.Next(1000);
Console.WriteLine(number);
});
No, the C# Random
class is not thread-safe. It maintains internal state that can be corrupted when accessed by multiple threads simultaneously. Here are three ways to make the Random
class thread-safe:
// This demonstrates thread safety issues with Random
using System;
using System.Threading.Tasks;
class RandomThreadSafetyDemo
{
// Shared Random instance - NOT thread-safe
private static Random sharedRandom = new Random();
// Thread-safe approach using ThreadLocal
private static ThreadLocal<Random> threadLocalRandom = new ThreadLocal<Random>(() => new Random());
// Another thread-safe approach using lock
private static object lockObject = new object();
public static void DemonstrateThreadSafetyIssues()
{
// This can produce duplicate numbers due to thread safety issues
Parallel.For(0, 100, i =>
{
int number = sharedRandom.Next(1000);
Console.WriteLine($"Unsafe number: {number}");
});
}
public static void ThreadSafeApproach1()
{
// Using ThreadLocal - each thread gets its own Random instance
Parallel.For(0, 100, i =>
{
int number = threadLocalRandom.Value.Next(1000);
Console.WriteLine($"Thread-local number: {number}");
});
}
public static void ThreadSafeApproach2()
{
// Using local copy of Random with unique seed
Parallel.For(0, 100, i =>
{
var localRandom = new Random(Guid.NewGuid().GetHashCode()); // Unique seeds with local copy of Random
var number = localRandom.Next(1000);
Console.WriteLine($"Safe number: {number}");
});
}
public static void ThreadSafeApproach3()
{
// Using lock - serializes access to shared Random
Parallel.For(0, 100, i =>
{
int number;
lock (lockObject) // May have concurrency issues and less performance, but yes, thread-safe
{
number = sharedRandom.Next(1000);
}
Console.WriteLine($"Locked number: {number}");
});
}
}
Comment