Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Random.Next() sometimes returns same number in separate threads

I have the following class

class Program
{
   static Random _Random = new Random();

   static void Main(string[] args)
   {
      ...
      for (int i = 0; i < no_threads; ++i)
      {
         var thread = new Thread(new ThreadStart(Send));
         thread.Start();
      }
      ...   
   }

   static void Send()
   {
      ...
      int device_id = _Random.Next(999999);
      ...
   }
}

The code creates the specified number of threads, starts each one, and assigns each thread a random device_id. For some reason, the first two threads that are created often have the same device_id. I can't figure out why this happens.

like image 812
dandan78 Avatar asked Jan 06 '11 09:01

dandan78


3 Answers

Random is not thread-safe - you shouldn't be using the same instance from multiple threads. It can get much worse than just returning the same data - by using it from multiple threads, you can get it "stuck" in a state where it will always return 0, IIRC.

Obviously you don't just want to create a new instance for each thread at roughly the same time, as they'll end up with the same seeds...

I have an article which goes into the details of this and provides an implementation which lazily instantiates one instance of Random per thread using an incrementing seed.

like image 78
Jon Skeet Avatar answered Oct 23 '22 20:10

Jon Skeet


Random is a pseudo-random number generator and there's nothing preventing it from returning same result for multiple calls. After all there's a probability for this happening. Not to mention that according to the documentation:

Any instance members are not guaranteed to be thread safe.

So you shouldn't be calling the Next method at all from multiple threads.

like image 5
Darin Dimitrov Avatar answered Oct 23 '22 19:10

Darin Dimitrov


Your example code only shows one use of _Random per thread. Assuming this is the case, you could also generate the random number in the main for loop and pass the random number into each thread as a parameter.

 for (int i = 0; i < no_threads; ++i)
 {
      var thread = new Thread(new ThreadStart(Send));
      thread.Start(_Random.Next(999999));
 }

and then modify your thread function to accept the parameter:

 static void Send(int device_id)
 {
    ...
    //int device_id = _Random.Next(999999);
    ...
 }   
like image 2
Grhm Avatar answered Oct 23 '22 20:10

Grhm