Извините за глупый вопрос, но только начал узнавать о Threads и Invoke. Почему этот код выполняется без каких-либо исключений:
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(DoStuff1);
thread.Name = "new thread";
thread.Start();
}
private void DoStuff1()
{
this.label1.Invoke((MethodInvoker)(() => label1.Text = "info from new thread"));
button1.BackColor = Color.Red;
DoStuff2();
}
private void DoStuff2()
{
label1.Text = "info from new thread";
}
Почему тело метода DoStuff2 выполняется, несмотря на то, что мы пытаемся изменить управление, созданное UI-потоком, из совершенно другого потока. И кстати, если мы немного изменим метод DoStuff2, и изменим текст, например на info from new thread2, то появится Exception. Это какая-то спецификация языка, он сравнивает тексты и, если они совпадают, ничего не делает? И, кстати, почему этот код выполняется без Exception button1.BackColor = Color.Red, здесь мы тоже балуемся с управлением в UI-потоке.
Настоящий вопрос заключается в том, почему вы используете необработанные потоки и Invoke, когда async/await и Task.Run доступны в течение 8 лет? Вы даже не упомянули, какой фреймворк используется. Может быть, просто возможно, изменение цвета не приводит к броску, потому что это не влияет на элемент управления, пока его не нужно перерисовывать. Изменение текста означает, что элемент управления должен измениться немедленно. Это может быть задокументировано или случайно. Хотя весь код плохой
@PanagiotisKanavos спасибо за ваш ответ. Настоящий ответ - я только учусь. Я еще не использую его. Это просто тестовый код. Я нахожу интересное место в коде, и, поскольку я не смог найти документальный ответ на msdn и в любом другом месте, я решил спросить его здесь, потому что считаю это важным. Теперь я углублюсь и постараюсь улучшить качество своего кода. Спасибо за правильный путь.
Документированный ответ для всех ОС, начиная с 1990-х годов, никогда не модифицирует пользовательский интерфейс из другого потока. Не только для Windows — Linux (в частности, оконные менеджеры) и MacOS имеют такое же ограничение. Некоторые фреймворки будут сбрасываться до того, как пользовательский интерфейс будет искажен, некоторые - нет. .NET вообще не жаловался до 4.0.
Я предполагаю, что вы проводите тесты в приложении WinForms. Попробуйте добавить это при запуске вашей программы: Control.CheckForIllegalCrossThreadCalls = true;, чтобы увидеть, имеет ли это какое-то значение.





Резюмируя комментарии:
Обновление объектов пользовательского интерфейса из фонового потока всегда небезопасно:
Отладчик Visual Studio обнаруживает эти вызовы небезопасных потоков, вызывая InvalidOperationException с сообщением Недопустимая операция между потоками. Элемент управления "" доступен из потока, отличного от потока, в котором он был создан. InvalidOperationException всегда возникает для небезопасных вызовов между потоками во время отладки Visual Studio и может возникать во время выполнения приложения. Вы должны решить эту проблему, но вы можете отключить исключение, установив для свойства Control.CheckForIllegalCrossThreadCalls значение false.
От Делайте потокобезопасные вызовы к элементам управления Windows Forms. Большинство фреймворков пользовательского интерфейса, как правило, запрещают вызовы между потоками, поэтому это не уникально для оконных форм.
Правильный способ - убедиться, что вы обновляете пользовательский интерфейс только из основного потока. Шаблон async/await делает это довольно легко, если вы следуете общему шаблону и не делаете ничего странного.
private void button1_Click(object sender, EventArgs e){
// Do async call
var result = await SomeAsyncMethodCall();
// Update the UI
myTextbox.Text = result;
}
Тот факт, что некоторые элементы пользовательского интерфейса проверяют, вызываются ли они в правильном потоке, является просто проверкой безопасности и является деталью реализации. Он существует для вашего удобства (чтобы сообщить вам, что вы делаете неправильно, а не просто отображать странные вещи или прямой сбой), но вы не можете полагаться на него. В этом случае есть ранний выход, если не изменить текст, то есть проверка не сработает