Что плохого в вызове Invoke, независимо от InvokeRequired?


Я видел общую настройку для перекрестного потокового доступа к элементу управления GUI, как описано здесь: кратчайший способ записи потокобезопасного метода доступа к элементу управления windows forms

Все веб-хиты, которые я нашел, описывают одно и то же.

Однако, почему мы должны проверять InvokeRequired? Разве мы не можем просто вызвать Invoke напрямую?

Я предполагаю, что ответ-нет, поэтому мой настоящий вопрос- "почему"?

6 34

6 ответов:

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

Для потоков пользовательского интерфейса, однако-мы не хотим вызывать Invoke много времени; проблема в том, что если вы уже находитесь в потоке пользовательского интерфейса, он все еще имеет ненужные накладные расходы на отправку сообщения в насос формы и его обработку.

На самом деле, в большинстве потоковых кодов вы знайте вы ожидаете, что конкретный метод будет вызван в потоке не-UI, поэтому в этих случаях нет никаких дополнительных накладных расходов: просто вызовите Invoke.

InvokeRequired в основном говорит вам, если вы выполняете на правильном потоке или нет. Если вы не на правильном потоке, вам нужно маршалировать задачу на правильный поток, в противном случае вы этого не сделаете.

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

InvokeRequired проверяет идентичность текущего выполняющегося потока с идентичностью создаваемого потока. Если они одинаковы, то код может свободно взаимодействуйте с управлением. Если нет, то код должен маршалировать данные от текущего потока к потоку создания экземпляра. Это медленный и дорогостоящий процесс, и его следует избегать, если это вообще возможно. Ваш код будет работать, если вы всегда вызываете, и может оказаться, что вы не заметите снижения производительности, но этот сценарий будет все более распространенным, когда многоядерные системы войдут в употребление. Лучше всего не создавать кодовые "узлы", которые потом придется развязывать.

Если вы попытаетесь вызвать до того, как дескриптор окна будет создан (например, при вызове конструктора формы), вы получите InvalidOperationException. Итак, в общем случае требуется проверка InvokeRequired.

СмотритеMSDN для получения подробной информации.

Одна из причин, о которой я могу думать, - это производительность. Если большую часть времени вызывающий поток совпадает с создающим потоком, то у вас будут некоторые накладные расходы на unnessecry.

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

Его экономически эффективно вызывать Invoke только тогда, когда это требуется. Следовательно, InvokeRequired используется, чтобы узнать, выполняется ли вызов из того же потока или другого потока?