C# Multithreading Преминаване по стойност или препратка?

Видях част от код онлайн, който гласи, че извикването на нишка като тази причинява недетерминиран изход "0223557799" или нещо от този вид. (Разбрахте смисъла)

for (int i = 0; i < 10; i++)
   new Thread (() => Console.Write (i)).Start();

Това е причината за това:

"Проблемът е, че променливата i се отнася до едно и също място в паметта през целия живот на цикъла. Следователно всяка нишка извиква Console.Write върху променлива, чиято стойност може да се промени, докато работи!"

Но, конвенционално казано, когато аргументът се предава по стойност - всяко ново извикване на нишка трябва да изпраща i неговия инкрементален ред, нали? Само ако стойностите се предават чрез препратка, горепосочената причина е валидна. И така, в C# Multi-Threading стойностите предават ли се по референция?

Нов съм в C#, моля, разберете, ако въпросът е наивен.


person Learner    schedule 21.07.2013    source източник
comment
int temp = i; поставете го вътре в цикъла и преминете температурата, slaks е прав.   -  person terrybozzio    schedule 21.07.2013


Отговори (2)


Тук има повече от един проблем. Със сигурност започва с проблема за улавяне на променливата на цикъл for(), описан в това публикация в блог. Това има тенденция да произвежда "10" като изход, но няма гаранция, че това ще се случи, тъй като нишка може да се изпълни, докато цикълът все още се повтаря.

Но програмата страда и от проблем с основни нишки, няма никаква гаранция, че нишките ще извикат Console.Write() в очаквания ред. Това е само вероятно, но една нишка може да се състезава пред друга и да придобие ключалката, която защитава конзолата. Проблем, известен като „надпревара за нишки.

person Hans Passant    schedule 21.07.2013
comment
Промяната в C# 5 се прилага само за цикли foreach, не и за цикли. - person Eric Lippert; 21.07.2013

Вашата програма е еквивалентна на следната програма:

class Locals
{
    public int i;
    public void M() { Console.Write(this.i);
}

...
Locals locals = new Locals();
for (locals.i = 0; locals.i < 10; locals.i++)
  new Thread (locals.M).Start();

Сега ясно ли е защо получавате резултатите, които постигате? Не i се предава по стойност; по-скоро locals се предава по препратка към всяка нишка. Всяка нишка споделя locals.i и следователно може да види текущата стойност на locals.i, а не стойността, която i е била при създаването на нишката.

person Eric Lippert    schedule 21.07.2013