Каково определение потока пользовательского интерфейса? В приложении .NET есть только один поток пользовательского интерфейса?

Что такое поток пользовательского интерфейса? В приложении .NET есть только один поток пользовательского интерфейса?


person Community    schedule 04.05.2010    source источник


Ответы (3)


(Упрощение вперед)

Поток пользовательского интерфейса — это поток Single Threading Apartment, который используется для создания различных объектов пользовательского интерфейса (в Winforms это означает элементы управления). По соглашению и правилу доступ к элементу управления может быть только из потока, который использовался для его создания; в противном случае могут и будут получены неожиданные результаты, от визуальных странностей вплоть до аварии.

Если вы явно не создадите больше, в приложении Windows Forms будет только один поток пользовательского интерфейса. Хотя вы можете создать другой поток и запустить цикл обработки сообщений, существует очень мало причин, по которым вы хотели бы это сделать, и два разных потока пользовательского интерфейса не могут «общаться» друг с другом больше, чем любой другой. поток может общаться с потоком пользовательского интерфейса.

person Adam Robinson    schedule 04.05.2010
comment
+1 за упоминание о том, что вы можете это сделать, но редко так нужно делать... - person Reed Copsey; 04.05.2010
comment
Так что насчет того, когда вы делаете new Thread().Start() внутри STAThread? - person ; 04.05.2010
comment
@Griever: Это запускает новый поток, но он полностью отделен от потока пользовательского интерфейса. Выполнение нового запуска потока в любом месте создает новый несвязанный поток. - person Reed Copsey; 04.05.2010
comment
@Reed: Вы имеете в виду, что если я создам элемент управления внутри Thread.Start, к этому элементу управления не будет прикреплен какой-либо насос сообщений? - person ; 04.05.2010
comment
@Гривер: Да. И если вы попытаетесь добавить его в другую форму, вы получите ошибки. В общем, плохая идея. (Вам нужно создать поток как поток STA, а затем также добавить насос сообщений в поток, а затем создать свою форму. Это позволяет вам запустить новый поток пользовательского интерфейса, но это действительно плохая идея - есть очень мало законных причин сделать это - поскольку вам почти всегда лучше просто перенести свою работу на фоновые потоки и оставить один поток пользовательского интерфейса на месте) - person Reed Copsey; 04.05.2010

Поток пользовательского интерфейса имеет ряд характеристик, которые делают его особенным:

  • В Windows есть очередь сообщений, связанная с потоком. Это происходит, как только в потоке создается самое первое окно.
  • Поток запускает цикл обработки сообщений, позволяя Windows отправлять сообщения окнам. Цикл сообщений создается, как только вы вызываете Application.Run().
  • COM был инициализирован в потоке, запросив однопоточное подразделение. STA необходима, чтобы обеспечить правильную работу многих функций Windows, функций, которые изначально не являются потокобезопасными. COM гарантирует, что эти функции всегда вызываются потокобезопасным способом, направляя вызов из рабочего потока в поток STA по мере необходимости. Примерами этих функций являются Drag+Drop, буфер обмена, диалоговые окна оболочки (OpenFileDialog и т. д.), элементы управления ActiveX, такие как WebBrowser, перехватчики окон, установленные SetWindowsHookEx, поставщики специальных возможностей, такие как используемые программой чтения с экрана, поставщики автоматизации пользовательского интерфейса. Весь внешний код, ни один из них не является потокобезопасным.
  • Поток никогда не блокируется ни при каких операциях, он остается отзывчивым, поэтому он может отправлять сообщения Windows по мере необходимости, чтобы поддерживать отзывчивость пользовательского интерфейса и поток запросов маршалинга COM. Например, вызовы WaitHandle.WaitAny() явно запрещены и генерируют исключение. CLR имеет особую поддержку функций WaitOne() и lock, запуская внутренний цикл обработки сообщений во избежание взаимоблокировок.

Поток запуска процесса почти всегда выбирается как поток пользовательского интерфейса, хотя это не является жестким требованием. Состояние STA выбирается атрибутом [STAThread] в методе Main().

Вы можете создать поток пользовательского интерфейса, убедившись, что вышеуказанные требования выполнены. Это может выглядеть так в приложении Winforms:

    var ui = new Thread(() => { Application.Run(new Form2()); });
    ui.SetApartmentState(ApartmentState.STA);
    ui.Start();

Это создает второе окно, работающее в собственном потоке пользовательского интерфейса. Одна типичная проблема, с которой вы сталкиваетесь при таком расположении, заключается в том, что теперь у вас есть два отдельных окна, они вообще не связаны друг с другом. 2-е окно не может принадлежать 1-му, оно имеет свой Z-порядок, независимый от 1-го. Трудно справиться с пользователем. Событие SystemEvents.UserPreferenceChanged примечательно тем, что оно неизбежно запускает свое событие в неправильном потоке, что может привести к взаимоблокировке. Многие элементы управления WinForms подписываются на него. За исключением редких случаев, таких как заставка, это совсем не улучшает пользовательский интерфейс.

person Hans Passant    schedule 04.05.2010

ОТРЕДАКТИРОВАНО для правильности:

Существует один поток пользовательского интерфейса для каждого активного ПРИЛОЖЕНИЯ в Windows Forms и аналогичная концепция для WPF.

то есть: когда вы запускаете приложение, есть один поток, он становится потоком пользовательского интерфейса, когда Application.Run(new Form1()); называется.

Если вы попытаетесь выполнить Application.Run(new Form2()); во время выполнения вы получите «System.InvalidOperationException: запуск второго цикла сообщений в одном потоке не является допустимой операцией. Вместо этого используйте Form.ShowDialog».

Если вам действительно нужны две отдельные формы, чтобы не использовать один и тот же поток, вам нужно будет создать новый поток, а затем вызвать Application.Run(new MyForm()) и т.д. и т.д. Это не распространено.

person David    schedule 04.05.2010
comment
Это неправда. Различные формы в Windows Forms используют один и тот же поток. Насос сообщений заставляет их всех реагировать. - person Reed Copsey; 04.05.2010
comment
У меня было наоборот, модальные диалоги требуют нового потока, немодальные диалоги не требуют нового потока. Дело в том, что обычные потоки могут стать потоками пользовательского интерфейса, когда из них запускается новая форма. - person David; 04.05.2010
comment
Это все еще неправда. Запуск формы из нового потока без особой заботы о запуске цикла сообщений вызовет всевозможные проблемы, включая (в большинстве случаев) сбой из-за отсутствия STA по умолчанию. - person Reed Copsey; 04.05.2010
comment
Вы можете быть правы. В прошлом был случай, когда я пытался показать форму и во время выполнения получил сообщение об ошибке, говорящее мне, что я не могу открыть две формы в одном и том же потоке пользовательского интерфейса, я пытаюсь отследить это, чтобы прокомментировать здесь, но я не еще не нашел - person David; 04.05.2010
comment
Только что отредактировал свой пост, я путал Application.Run с Form.Show. - person David; 04.05.2010