Межпоточная обработка событий в C # - PullRequest
11 голосов
/ 29 января 2010

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

class SomeDataSource {

    public event OnFrameworkEvent;

    void FrameworkCallback() {

        // This function runs on framework's thread.

        if (OnFrameworkEvent != null)
            OnFrameworkEvent(args);
    }
}

Я хочу доставить эти события объекту Winforms в потоке Winforms. Я, очевидно, проверяю InvokeRequired и отправляю его в поток Winforms, если это необходимо.

class SomeForm : Form {

    // ...

    public void SomeAction(SomeArgs args) {
        if (InvokeRequired) {
            BeginInvoke(new Action(SomeAction), args);
            return;
        }

        // ...
    }

}

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

var form = new SomeForm();
var src = new SomeDataSource();

// ...

src.OnFrameworkEvent += form.SomeAction;
form.Closing += (sender, eargs) => src.OnFrameworkEvent -= form.SomeAction;
  1. Теперь, является ли этот подход потокобезопасным? Если форма находится в процессе закрытия, а внешний поток вызывает BeginInvoke, вызов все равно будет поставлен в очередь на выполнение, если форма закрыта? (что означает, что у меня все еще есть шанс столкнуться с той же проблемой)

  2. Есть ли лучший подход или рекомендуемый шаблон для обработки событий между потоками?

Ответы [ 3 ]

4 голосов
/ 29 января 2010

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

Проверьте эту тему для получения дополнительной информации.

2 голосов
/ 03 февраля 2012

Вы можете добавить этот код в конструктор CheckForIllegalCrossThreadCalls = false;, и исключение не будет выдано.

1 голос
/ 29 января 2010

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

  1. Этот подход не является потокобезопасным. Вызов все равно будет вызван, даже если сама программа закрыта. Я видел это в диспетчере задач (после закрытия программы, как вы говорите) как зависание потоков. (даже если вы убьете программу из диспетчера задач). Я должен был убить эти темы отдельно позже.

  2. Когда форма закрывается, вам нужно убить поток диспетчера, чтобы он не зависал, если в этом потоке что-то не так.

    form.Closing += (sender, eargs) => src.OnFrameworkEvent -= form.SomeAction;
     // pseudo-code (find c# equivalent)
    if (dispatcherthread.isrunning)
    dispatcherThread.kill();
    
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...