С#: внутренняя работа: события, Control.BeginInvoke и выход из программы = прерывание?

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

Поскольку я использую асинхронные сокеты, некоторые из этих сообщений возвращаются в разных потоках, поэтому, как только они попадают в основной поток, я проверяю InvokeRequired, и если это правда, я использую this.BeginInvoke для обработки журнала.

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

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

Мой вопрос касается понимания того, как работают события и BeginInvoke в случае завершения программы. Если событие находится в очереди или непосредственно перед закрытием программы был вызван BeginInvoke, будет ли оно немедленно завершено, отменив все? или он выполнит все ожидающие действия, в моем случае зарегистрирует ожидающее сообщение, а затем выйдет?


person 537mfb    schedule 15.03.2012    source источник
comment
Очередь вызовов очищается при удалении формы. Это не решает проблему, а только делает ее менее вероятной. Вы не можете позволить форме закрыться, пока не убедитесь, что вызовы больше не могут выполняться. Например, сначала закрыть сокеты.   -  person Hans Passant    schedule 15.03.2012
comment
Сначала я закрываю сокеты - и именно тогда мое событие журнала запускается - регистрируется, что сокет был закрыт - мой вопрос заключался в том, будет ли этот журнал всегда обрабатываться до закрытия программы или иногда программа может отменить это событие при закрытии, если все еще on queue или begininvoke еще не выполнены - ничего общего с удалением сокетов   -  person 537mfb    schedule 16.03.2012
comment
Очередь вызовов очищается при удалении формы. Путем удаления ожидающих вызовов, а не их выполнения.   -  person Hans Passant    schedule 16.03.2012
comment
Итак, все, что отложено с помощью BeginInvoke, не будет выполнено - спасибо - это все, что мне нужно было знать - теперь нужно найти способ убедиться, что этого не произойдет (получите неполный журнал в моем случае) - спасибо - сделайте это ответом я приму это   -  person 537mfb    schedule 16.03.2012


Ответы (2)


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

    private bool closing;

    protected override void OnFormClosing(FormClosingEventArgs e) {
        if (!closing) {
            closing = true;
            // Do your stuff
            //...
            this.BeginInvoke(new Action(() => this.Close()));
            e.Cancel = true;
        }
        base.OnFormClosing(e);
    }
person Hans Passant    schedule 16.03.2012
comment
Спасибо - очень признателен Ганс - отличное решение. Разве вы не должны были инициализировать закрытие значением false? - person 537mfb; 16.03.2012
comment
одно исправление в вашем коде - base.OnFormClosing(e); должен быть внутри, если оператор if - не снаружи - иначе я получаю исключение из стека - person 537mfb; 16.03.2012

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

Когда только что был вызван BeginInvoke, программа была немедленно завершена. Остальные операции (логирование) выполняться не будут, так как поток из пула потоков

person Toan Nguyen    schedule 16.03.2012
comment
Моя программа дала сбой, если я использовал Invoke (блокирующий) вместо BeginInvoke (неблокирующий) - он просто не выдавал никаких исключений. - person 537mfb; 16.03.2012