Invoke () блокирует

Время от времени графический интерфейс моих приложений перестает перерисовываться. Существует множество потоков, которые запускают всевозможные события (например, таймеры, готовность сетевых данных и т. д.). Также есть много элементов управления, которые подписываются на эти события. Из-за этого все обработчики событий играют в игру InvokeRequired / Invoke. Теперь я понял, что когда GUI зависает, многие потоки ждут возврата Invoke (). Похоже, сообщение помпа перестала качать. Обработчики выглядят так:

private void MyEventHandler( object sender, EventArgs e ) {
    if ( InvokeRequired ) {
        Invoke( new EventHandler( MyEventHandler ), sender, e );
        return;
    }

    SetSomeStateVariable();
    Invalidate();
}

Есть идеи?

Решение: BeginInvoke (). Похоже, вы всегда должны использовать BeginInvoke (), если у вас много CrossThread-Events ...

Спасибо.

Спасибо всем.

Обновлено: Похоже, BeginInvoke() действительно решил эту проблему. До сих пор не замерзало.

Кого выстраивают, когда он замерзает? Это один конкретный элемент управления или событие, или это случайность?

user1228 13.11.2008 17:58

Я не совсем понимаю, что ты имеешь в виду.

EricSchaefer 13.11.2008 18:03

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

user1228 13.11.2008 18:08

Не знаю, потому что ловил в отладчике всего один раз. «Время от времени» в данном случае означает «возможно, десять раз за 6 месяцев и только один раз на коробке с отладчиком».

EricSchaefer 13.11.2008 18:26
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
21
4
12 711
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

Вы можете увидеть это с подключенным отладчиком? Если это так, сделайте его «замороженным», а затем нажмите кнопку «пауза» - и посмотрите, что делает поток пользовательского интерфейса.

Обратите внимание: если вы можете обойтись без BeginInvoke вместо Invoke, жизнь станет немного проще, так как он не будет блокировать.

Также обратите внимание, что вам не нужен бит «new EventHandler» - просто

Invoke((EventHandler) MyEventHandler, sender, e);

все должно быть в порядке.

Просто по памяти: я думаю, вам следует вызвать Invoke () для соответствующего элемента управления. Затем элемент управления должен выполнить метод в потоке графического интерфейса. Скажите, пожалуйста, если я ошибаюсь.

lowglider 13.11.2008 18:15

@EricShaefer: Если вы откроете стек для каждого потока, должно быть довольно очевидно, что это за поток пользовательского интерфейса :)

Jon Skeet 13.11.2008 18:42
Ответ принят как подходящий

Invoke ждет, пока событие не будет обработано в потоке графического интерфейса. Если вы хотите, чтобы это было асинхронно, используйте BeginInvoke ()

Я знаю это. BeginInvoke, вероятно, просто скроет проблему. Все вызовы блокируются на неопределенный срок.

EricSchaefer 13.11.2008 18:04

Эрик Шефер, вы упускаете суть. Invoke ожидает завершения вызванного вами события. Однако вызов будет вызван только после завершения выполнения текущей функции. Вы зашли в тупик. BeginInvoke не будет ждать выполнения вызываемой функции, поэтому нет взаимоблокировки.

Joel Lucsy 13.11.2008 18:16

Возможно, мне не хватает одного пункта. Событие, вызывающее MyEventHandler, запускается другим потоком (например, тем, который ожидает данных из сети), а не событием пользовательского интерфейса. И зависает только «время от времени».

EricSchaefer 13.11.2008 18:28

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

Joel Coehoorn 13.11.2008 18:39

Ох, хорошо. Теперь я понимаю. Я попробую это. Но, пожалуйста, не задерживайте дыхание, потому что проблему нелегко воспроизвести. Спасибо.

EricSchaefer 13.11.2008 18:42

Я попытался зарегистрировать вызывающий ошибку Invoke (см. Сообщение Wills), и до сих пор графический интерфейс не зависал. Я изменил все Invoke () на BeginInvoke (). Большое спасибо.

EricSchaefer 05.12.2008 11:24

Наиболее вероятный ответ (тупик) уже предложен.

Другой способ смоделировать это поведение - уменьшить количество потоков пула и портов завершения ввода-вывода; Вы случайно не звонили в ThreadPool.SetMaxThreads(...)?

Нет (для комментариев нужно не менее 10 символов ...)

EricSchaefer 13.11.2008 18:39

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

Я предлагаю вам создать статический класс, единственная цель которого - обрабатывать все ваши вызовы Invoke. Я бы предположил, что у этого класса есть метод, который принимает Control, (для вызова Invoke) Action (вызываемый метод) и описание (содержащее информацию, которую вам нужно знать, чтобы идентифицировать метод и что это такое. собираюсь сделать).

В теле этого метода я предлагаю вам поставить эту информацию (метод, описание) в очередь и немедленно вернуться.

Очередь должна обслуживаться одним потоком, который выталкивает пару действие / сообщение из очереди, записывает текущее время и описание действия в паре свойств, а затем вызывает действие (). Когда действие возвращается, описание и время очищаются (ваш DateTime может иметь значение NULL или установить для него значение DateTime.Max). Обратите внимание: поскольку все вызовы по одному направляются в поток пользовательского интерфейса, вы ничего не теряете, обслуживая очередь одним потоком.

А теперь вот где мы подошли к сути. Наш класс Invoking должен иметь поток System.Threading.Timer. Это НЕ должен быть объект windows.forms.timer, так как он выполняется в потоке пользовательского интерфейса (и будет заблокирован, когда пользовательский интерфейс заблокирован !!!).

Задача этого таймера - периодически проверять время вызова текущего действия. Если DateTime.Now - BeginTime> X, тактовый таймер определит, что это действие заблокировано. Контрольный таймер будет ЗАПИСЫВАТЬ (как бы вы ни регистрировали) ОПИСАНИЕ, записанное для этого Действия. Теперь у вас есть запись того, что происходило в то время, когда ваш пользовательский интерфейс заблокирован, и вы можете лучше отлаживать его.

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

Хорошие идеи. В любом случае мне придется перебрать все 55 (!) Вызовов.

EricSchaefer 14.11.2008 10:07

Когда я сделал то, что вы предложили, замораживания не произошло. Поэтому я изменил все Invoke () на BeginInvoke ().

EricSchaefer 05.12.2008 11:22

Другие вопросы по теме