#c# #multithreading #task
#c# #многопоточность #задача
Вопрос:
Я поиграл с потоками и задачами (.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 .Спящий режим (50) после потока.Start() только тогда результат выглядит так, как ожидалось
1
2
1
2
Мой вопрос:
- Почему, когда вы не ждете между запуском обоих потоков, первый поток теряет значение параметра метода, с которым вы изначально его запустили?
т.е. Первый поток запускается с параметром «1», второй поток запускается с параметром «2», однако параметр первого потока также становится «2»? Это не имеет смысла, тем более, что параметр метода Print() является типом значения string .
Комментарии:
1. Спасибо за все ответы.
Ответ №1:
Google «доступ к измененному закрытию». Происходит то, что ваша локальная переменная «item» изменяет свое значение до вызова функции печати. Решением было бы создать новую переменную внутри области действия цикла и назначить ей элемент.
Ответ №2:
Элемент вычисляется во время запуска созданного вами потока из-за закрытия c #. Другой способ принудительно вычислить элемент — ввести переменную, чтобы закрытие включало ее следующим образом:
foreach (var item in items)
{
var closedItem = item;
var thread = new Thread(() => Print(closedItem));
thread.Start();
}
Ответ №3:
Ваша проблема не в потоках. Ваша проблема связана с закрытием и foreach. Вы можете прочитать здесь, почему: http://blogs.msdn.com/b/ericlippert/archive/2009/11/12/closing-over-the-loop-variable-considered-harmful.aspx
Когда вы играете с синхронизацией потоков, вы также переупорядочиваете тайминги основного потока, поэтому иногда цикл будет выполняться до запуска метода печати нового потока, а иногда и после.
Ответ №4:
Покажите нам код запуска потока, и вы обнаружите, что вы передаете не постоянную строку, а ссылочную переменную, и в промежутках между вызовами этих методов запуска вы, вероятно, меняете переменную.