Почему в WinForms вы не можете обновлять элементы управления пользовательского интерфейса из других потоков?

Я уверен, что для этого есть веская (или, по крайней мере, достойная) причина. Что это?

я думаю, что это - блестящий вопрос - и я думаю, что есть потребность лучшего ответ.

Конечно, единственная причина - это там что-то в структуре где-нибудь это isn' t очень безопасный от нити.

Это " something" почти каждый участник случая на каждом контроле в Системе. Windows. Формы.

Документация MSDN для многих средств управления в Системе. Windows. Формы, если не все они, говорят " Любая статичная общественность (Разделенный в Visual Basic) члены этого типа является безопасной нитью. Любые участники случая, как гарантируют, не будут безопасной &quot нитью;

Это означает что участники случая, такие как 'TextBox. Текст {добирается; набор;}' не reentrant .

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

[Отредактировать]

Хотя этот вопрос только спрашивает " why" вот связь со статьей, которая объясняет " how":

Как к: сделайте безопасные от нити звонки Windows Forms Controls на MSDN

http://msdn.microsoft.com/en-us/library/ms171728.aspx

Комментарии (1)
Решение

Потому что вы можете легко зайти в тупик (среди прочих проблем).

Например, ваш вторичный поток может пытаться обновить элемент управления пользовательского интерфейса, но элемент управления пользовательского интерфейса будет ждать освобождения ресурса, заблокированного вторичным потоком, поэтому оба потока будут ждать завершения друг друга. Как отмечали другие, эта ситуация не уникальна для кода пользовательского интерфейса, но встречается особенно часто.

В других языках, таких как C++, вы можете попытаться сделать это (без исключения, как в WinForms), но ваше приложение может зависнуть и перестать отвечать, если возникнет тупик.

Кстати, вы можете легко сообщить потоку UI, что хотите обновить элемент управления, просто создайте делегат, затем вызовите (асинхронный) метод BeginInvoke на этом элементе управления, передав ему свой делегат. Например.

myControl.BeginInvoke(myControl.UpdateFunction);

Это эквивалентно выполнению C++/MFC PostMessage из рабочего потока

Комментарии (2)

Хотя это кажется разумным ответом Джонса isn' t правильный. На самом деле, даже когда использование Призывает you' ре, все еще безопасное не столкновение с ситуациями тупика. Когда контакт с событиями стрелял в фоновое использование нити, Призывают, мог бы даже привести к этой проблеме.

< br/>

Настоящая причина больше имеет отношение к условиям гонки и отводит назад в древние времена Win32. Я can' t объясняют детали здесь, ключевые слова - насосы сообщения, события WM_PAINT и тонкие различия между " SEND" и " POST".

< br/>

Дополнительная информация может быть найдена здесь здесь и здесь.

Комментарии (0)

В версиях 1.0/1.1 исключения при отладке не возникало, вместо этого возникал периодический сценарий зависания во время выполнения. Класс! :) Поэтому в версии 2.0 они сделали так, чтобы этот сценарий выбрасывал исключение, и совершенно справедливо.

Фактическая причина этого, вероятно (как утверждает Адам Хейл), заключается в каком-то параллелизме/проблеме блокировки. Обратите внимание, что обычный .NET api (например, TextBox.Text = "Hello";) оборачивает команды SEND (которые требуют немедленного действия), что может создать проблемы, если они выполняются в отдельном потоке от того, который выполняет обновление. Использование Invoke/BeginInvoke вместо этого использует POST, который ставит действие в очередь.

Более подробная информация о SEND и POST здесь.

Комментарии (0)

Также была бы потребность осуществить синхронизацию в функциях обновления, которые чувствительны к тому, чтобы быть названным одновременно. Выполнение этого для элементов UI было бы дорогостоящим и в применении и в уровнях OS, и абсолютно избыточным для подавляющего большинства кодекса.

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

Комментарии (0)

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

Редактировать:

В других языках, таких как C++ вы свободно можете попытаться сделать это (без исключения, как в WinForms), но вы > в конечном счете, научитесь нелегкому пути!

Ах да... Я переключаюсь между C/C++ и C# и поэтому был немного более общим, чем должен был, извините... Он прав, вы можете сделать это в C/C++, но это вернется, чтобы укусить вас!

Комментарии (0)

Хм I' m не вполне уверенный, но я думаю, что, когда у нас есть прогресс средства управления как бары ожидания, индикаторы выполнения, мы можем обновить их ценности от другой нити, и все работает отлично без любых затруднений.

Комментарии (0)