Почему Crossthreading работает таким образом?
решаемые
Кажется, что Оливер прав. После нескольких попыток я получил исключение, и в режиме отладки я получаю это точно. Так что это должно быть все время. Вы также должны проверить ответ Мэтью Ваттонса;)
Пример
Прежде всего небольшой пример, который объяснит мое замешательство.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace testCrossThreading
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
new Thread(ThreadJob).Start();
}
void ThreadJob()
{
//label1.Text = "1";
changeText(label1, "1");
}
void changeText(Label L, String message)
{
L.Text = message;
}
}
}
Вопрос
Итак, теперь мой вопрос: если я раскомментирую label1.Text = "1";
в функции "ThreadJob", тогда я получаю исключение перекрестного потока, как ожидалось.
Но если я оставлю его прокомментированным, как показано на примере, он действительно работает. Но почему?
Функция вызывается вспомогательным потоком, и я ничего не вызываю. Таким образом, это все еще вспомогательный поток, а не поток GUI, который изменяет текст метки imo. Или я что-то упускаю?
Я бы написал это так.
void ThreadJob()
{
Action a = () => label1.Text = "1";
this.Invoke(a);
}
Ответы
Ответ 1
Я думаю, что это просто вопрос времени. Если вы попытаетесь обновить элемент gui из потока, отличного от gui, будет выбрано исключение перекрестного потока . Вы даже можете отключить все исключения кросс-потоков, вызвав
Form.CheckForIllegalCrossThreadCalls = false;
но после того, как исключение исчезло, дальнейшее поведение undefined и может привести к очень тонким ошибкам. Поэтому возьмите исключение в качестве подсказки для запаха кода, но помните, что иногда исключение не будет выбрано, даже если оно должно быть.
Ответ 2
Я думаю, что у вас может быть состояние гонки, поэтому результаты меняются.
Если вы попытаетесь изменить свойство Text
элемента управления, который в настоящее время не отображается, тогда .Net не заботится о том, какой поток меняет его.
В вашем коде вы начинаете поток с конструктора. Код, который фактически отображает форму, может отображаться или не отображаться перед тем, как код в потоке, который устанавливает свойство, выполняется.
Когда вы вызываете дополнительную функцию для установки свойства, тайминги изменяют и выставляют условия гонки.
Вы можете проверить это, добавив Thread.Sleep(100)
в начало ThreadJob()
.