Что случилось с вызовом Invoke, независимо от InvokeRequired?

Я видел общую настройку для кросс-потокового доступа к элементу управления графическим интерфейсом, например, обсуждаемый здесь: Самый короткий способ написать поточно-безопасный метод доступа к управлению формами окон

Все найденные веб-хиты описывают аналогичную вещь.

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

Я предполагаю, что ответ отрицательный, поэтому мой реальный вопрос: "почему"?

Ответ 1

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

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

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

Ответ 2

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

Ответ 3

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

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

Ответ 4

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

Подробнее см. MSDN.

Ответ 5

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

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

Ответ 6

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