Каждый поток получает свой собственный стек.Проблема, с которой вы столкнулись, не имеет ничего общего со стеком.Проблема в том, как он генерирует код для вашего анонимного делегата.Используйте инструмент вроде рефлектора, чтобы понять код, который он генерирует.Следующее исправит вашу проблему:
static void Main()
{
for (int i = 0; i < 10; i++)
{
int capture = i;
new Thread(() => Console.Write(capture)).Start();
}
}
Под капотом
Всякий раз, когда вы используете переменную из внешней области видимости (в вашем случае переменная i) в анонимном делегатекомпилятор генерирует новый класс, который упаковывает анонимную функцию вместе с данными, которые он использует из внешней области видимости.Таким образом, в вашем случае сгенерированный класс содержит - одну функцию и элемент данных для захвата значения переменной i.Определение класса выглядит примерно так:
class SomeClass
{
public int i { get; set; }
public void Write()
{
Console.WriteLine(i);
}
}
Компилятор переписывает ваш код следующим образом:
SomeClass someObj = new SomeClass();
for (int i = 0; i < 10; i++)
{
someObj.i = i;
new Thread(someObj.Write).Start();
}
и, следовательно, проблема - с которой вы столкнулись.Когда вы захватываете переменную, компилятор делает следующее:
for (int i = 0; i < 10; i++)
{
SomeClass someObj = new SomeClass();
someObj.i = i;
new Thread(someObj.Write).Start();
}
Обратите внимание на разницу в создании экземпляров SomeClass.Когда вы захватываете переменную, она создает столько экземпляров, сколько существует итераций.Если вы не захватываете переменную, она пытается использовать один и тот же экземпляр для всех итераций.
Надеюсь, приведенное выше объяснение прояснит ваши сомнения.
Спасибо