Random.Next () иногда возвращает одно и то же число в отдельных потоках - PullRequest
10 голосов
/ 06 января 2011

У меня есть следующий класс

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);
      ...
   }
}

Код создает указанное количество потоков, запускает каждый из них и присваивает каждому потоку случайное значение device_id. По некоторым причинам первые два создаваемых потока часто имеют одинаковые значения device_id. Я не могу понять, почему это происходит.

Ответы [ 3 ]

26 голосов
/ 06 января 2011

Random не является потокобезопасным - вы не должны использовать один и тот же экземпляр из нескольких потоков. Это может быть гораздо хуже, чем просто возвращать одни и те же данные - используя их из нескольких потоков, вы можете «застрять» в состоянии, когда они будут всегда возвращать 0, IIRC.

Очевидно, что вы не просто хотите создать новый экземпляр для каждого потока примерно в одно и то же время, так как они получат одинаковые семена ...

У меня есть статья , которая углубляется в детали этого и предоставляет реализацию, которая лениво создает один экземпляр Random для потока, используя увеличивающееся начальное число.

5 голосов
/ 06 января 2011

Случайно - генератор псевдослучайных чисел, и ничто не мешает ему возвращать один и тот же результат для нескольких вызовов.В конце концов, есть вероятность этого.Не говоря уже о том, что в соответствии с документацией :

Ни один из членов экземпляра не гарантированно является потокобезопасным.

Так что вам не следуетвызов метода Next из нескольких потоков.

2 голосов
/ 06 января 2011

Ваш пример кода показывает только одно использование _Random на поток.Предполагая, что это так, вы также можете сгенерировать случайное число в основном цикле for и передать случайное число в каждый поток в качестве параметра.

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

, а затем изменить функцию потока, чтобы она принималапараметр:

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