Concurrency problems with Random in .Net?

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 .

+6
source share
4 answers

For some strange reason

This is not very strange - Random is not documented to be thread safe.

This is pain, but this life. For more information, see the article on randomness and suggestions on how to have an instance per thread, with protection against starting with the same seed in multiple threads.

+17
source

The Random class is not thread safe.

In docs :

 Any instance members are not guaranteed to be thread safe 

Instead of synchronizing, which will block all threads, try using the ThreadStatic attribute.

+8
source

Thread safety is not accidentally guaranteed: http://msdn.microsoft.com/en-us/library/system.random.aspx , unless it is public static.

+1
source

Unfortunately, this is correct, you need to be careful when using Random Class.

Here are two blog posts with more details, comments, and code examples on this topic:

The worst part of this behavior is that it just stops working (i.e. as soon as the problem occurs, the return value from random.Next .... methods is 0)

+1
source

Source: https://habr.com/ru/post/887472/


All Articles