Запуск нескольких потоков, почему вы должны ждать? - PullRequest
1 голос
/ 01 ноября 2011

Я поиграл с Threads и Tasks (.net 4) и заметил странное поведение при запуске нескольких потоков без ожидания нескольких миллисекунд между каждым вызовом потока.

В приведенном ниже примере при запуске не выводится то, что я ожидал:

1
2
1
2

Но вместо этого выводятся только:

2
2
2
2

Ниже приведен код, который я запускаю.

public static void Main()
{
    var items = new[] {"1", "2"};
    foreach (var item in items)
    {
      var thread = new Thread(() => Print(item));          
      thread.Start();
      //var task = Task.Factory.StartNew(() => Print(item));               
    }
}

static void Print(string something)
{
  while (true)
  {
    Console.WriteLine(something);
    Thread.Sleep(1000);
  }
}

Теперь, когда я вызываю Thread.Sleep (50) после thread.Start (), тогда только результат будет выглядеть как положено

1
2
1
2

Мой вопрос:

  • Почему, когда вы не ждете между запуском обоих потоков, первый поток теряет значение параметра метода, с которого вы его изначально запустили?

т.е. первый поток запускается с параметром "1", второй поток запускается с параметром "2", однако параметр первого потока также становится "2"?Это не имеет смысла, тем более что параметр метода Print () является типом значения строки.

Ответы [ 4 ]

5 голосов
/ 01 ноября 2011

Google "доступ к измененному закрытию". То, что происходит, - это то, что ваша локальная переменная "item" получает свое значение перед вызовом функции Print. Решением было бы создать новую переменную внутри области действия цикла и назначить ей элемент.

2 голосов
/ 01 ноября 2011

Элемент оценивается во время запуска создаваемого вами потока из-за замыканий в c #.Другой способ заставить элемент оценить - ввести переменную так, чтобы замыкание включало его следующим образом:

foreach (var item in items)     
        {
            var closedItem = item;
            var thread = new Thread(() => Print(closedItem));                 
            thread.Start();       
        } 
1 голос
/ 01 ноября 2011

Ваша проблема не с потоками. Ваша проблема с закрытием и foreach. Вы можете прочитать здесь, почему: http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx

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

0 голосов
/ 01 ноября 2011

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

...