I am debugging some problems with the Paint.Net plugin , and I came across some problems with the Random class when multiple threads call a method from one instance.
For some strange reason, it seems that if I don't prevent simultaneous access by synchronizing the called method, my random instance starts to behave ... randomly (but in a bad sense).
In the following example, I create several hundred threads that repeat one random object. And when I run it, I sometimes (not always, but almost) get obviously incorrect results. The problem NEVER arises if I uncomment the annotation of the Synchronized method.
using System; using System.Threading; using System.Runtime.CompilerServices; namespace testRandom { class RandTest { static int NTIMES = 300; private long ac=0; public void run() { // ask for random number 'ntimes' and accumulate for(int i=0;i<NTIMES;i++) { ac+=Program.getRandInt(); System.Threading.Thread.Sleep(2); } } public double getAv() { return ac/(double)NTIMES; // average } } class Program { static Random random = new Random(); static int MAXVAL = 256; static int NTREADS = 200; //[MethodImpl(MethodImplOptions.Synchronized)] public static int getRandInt() { return random.Next(MAXVAL+1); // returns a value between 0 and MAXVAL (inclusive) } public static void Main(string[] args) { RandTest[] tests = new RandTest[NTREADS]; Thread[] threads = new Thread[NTREADS]; for(int i=0;i<NTREADS;i++) { tests[i]= new RandTest(); threads[i] = new Thread(new ThreadStart(tests[i].run)); } for(int i=0;i<NTREADS;i++) threads[i].Start(); threads[0].Join(); bool alive=true; while(alive) { // make sure threads are finished alive = false; for(int i=0;i<NTREADS;i++) { if(threads[i].IsAlive) alive=true; } } double av=0; for(int i=0;i<NTREADS;i++) av += tests[i].getAv(); av /= NTREADS; Console.WriteLine("Average:{0, 6:f2} Expected:{1, 6:f2}",av,MAXVAL/2.0); Console.Write("Press any key to continue . . . "); Console.ReadKey(true); } } }
Example output (with the above values):
Average: 78.98 Expected:128.00 Press any key to continue . . .
Is this a known issue? Is it wrong to call a random object from multiple threads without synchronization?
UPDATE: according to the answers, the docs indicate that the Random methods are not thread safe - mea culpa, I should have read this. Maybe I read it before, but I didn’t think it was so important - you can (sloppily) think that in the rare case when two threads enter the same method at the same time, the worst thing that can happen is that these calls get the wrong results - not a huge deal, if we are not too concerned about the quality of random numbers ... But the problem is really catastrophic, because the object remains in an inconsistent state, and from the fact that it returns, continues to return zero - as noted here .
source share