Зачем использовать BeginInvoke здесь? - PullRequest
4 голосов
/ 18 февраля 2010

Я изучаю чужой код и не имею большого опыта работы с многопоточностью Я наткнулся на эту строку кода:

BeginInvoke((MethodInvoker)delegate() { btnCalibrate.PerformClick(); });

Мне было интересно, зачем это делать, если только это сработало бы:

Спасибо за ваши ответы.

Ответы [ 2 ]

6 голосов
/ 18 февраля 2010

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

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

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

1 голос
/ 18 февраля 2010

Чтобы немного расширить @Earwicker - Control.BeginInvoke - это способ передачи вызова из одного потока в поток, которому принадлежит экземпляр Control. В фоновом режиме он использует сообщения Win32 через функцию Win32 с именем PostMessage, чтобы маршалировать вызов метода PerformClick в потоке-владельце. Это необходимо из-за Windows Win32 и расширения WinForms Controls, обеспечивающего безопасный доступ только из потока, который его создал, который обычно является единственным потоком, выполняющим графический интерфейс.

Причина использования BeginInvoke против Invoke заключается в том, что первый использует PostMessage и возвращается сразу, а второй использует SendMessage под прикрытием и должен ждать PostMessage и ожидает ответа от потока GUI. Это может задержать выполнение потока вызовом или даже заблокировать приложение, поэтому BeginInvoke - лучший выбор здесь.

...