Отличающееся поведение при запуске потока: ParameterizedThreadStart по сравнению с Анонимным Делегатом.Какое это имеет значение?

Когда я работаю, код ниже вывода является "DelegateDisplayIt", обычно повторенным 1-4 раза. Я выполнил этот код, вероятно, 100 раз, и не однажды имеет вывод когда-либо "ParameterizedDisplayIt". Таким образом, это кажется способом, которым поток создается и впоследствии запустил влияние, как параметр передается. При создании нового потока с анонимным делегатом параметр является ссылкой назад на исходную переменную, но при создании с делегатом ParameterizedThreadStart параметр является совершенно новым объектом? Мое предположение кажется корректным? Если так, это кажется нечетным влиянием стороны конструктора потока, нет?

static void Main()
{
    for (int i = 0; i < 10; i++)
    {
        bool flag = false;

        new Thread(delegate() { DelegateDisplayIt(flag); }).Start();

        var parameterizedThread = new Thread(ParameterizedDisplayIt);
        parameterizedThread.Start(flag);

        flag = true;
    }

    Console.ReadKey();
}

private static void DelegateDisplayIt(object flag)
{
    if ((bool)flag)
        Console.WriteLine("DelegateDisplayIt");
}

private static void ParameterizedDisplayIt(object flag)
{
    if ((bool)flag)
        Console.WriteLine("ParameterizedDisplayIt");
}
5
задан Matthew Sposato 17 December 2009 в 19:09
поделиться

3 ответа

Ваше предположение верно. Оператор parameterizedThread.Start (flag) копирует флаговую переменную во время вызова.

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

5
ответ дан 13 December 2019 в 22:09
поделиться

флаг - это логическая переменная. Он передается делегату по значению. Это никогда не будет истинным, потому что ложное значение копируется и отправляется делегату.

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

В .NET компилятор создает анонимный тип для хранения ссылки на переменную, которая является предметом закрытия ( флаг ), которую анонимный делегат и метод затем будут ссылка. Затем они поделятся переменной, поэтому, если кто-то изменит ее, оба увидят изменение.

Это действительно не дискуссионный вопрос, речь идет о передаче по стоимости и закрытиях. Вот достойный пост в блоге о закрытии . Передача по значению довольно проста; Если вам нужно освежить в памяти это, я бы предложил купить копию CLR Via C # Джеффри Рихтера.

4
ответ дан 13 December 2019 в 22:09
поделиться

Let's take the first case:

for (int i = 0; i < 10; i++)
{
    bool flag = false;
    new Thread(delegate() { DelegateDisplayIt(flag); }).Start();
    flag = true;
}

Here when you construct the anonymous delegate the value of flag is false, but when the DelegateDisplayIt method executes, the flag has already been set to true by the next line, and you see the output displayed. Here's another example that illustrates the same concept:

for (int i = 0; i < 5; i++) 
{
    ThreadPool.QueueUserWorkItem(state => Console.WriteLine(i));
}

This will print five times five.

Now let's take the second case:

for (int i = 0; i < 10; i++)
{
    bool flag = false;
    var parameterizedThread = new Thread(ParameterizedDisplayIt);
    parameterizedThread.Start(flag);        
    flag = true;
}

the value passed to the callback is the one that the variable posses when you call the Start method, which is false and that's why you never see the output in the console.

1
ответ дан 13 December 2019 в 22:09
поделиться
Другие вопросы по тегам:

Похожие вопросы: