thread event handling in C#
I am working with a framework that runs its own event dispatcher in a separate thread. The framework may generate some events.
class SomeDataSource {
public event OnFrameworkEvent;
void FrameworkCallback() {
// This function runs on framework's thread.
if (OnFrameworkEvent != null)
OnFrameworkEvent(args);
}
}
I want to deliver these events to a Winforms object on Winforms thread. I obviously check for InvokeRequired
and dispatch it to Winforms thread if necessary.
class SomeForm : Form {
// ...
public void SomeAction(SomeArgs args) {
if (InvokeRequired) {
BeginInvoke(new Action(SomeAction), args);
return;
}
// ...
}
}
Now events may be delivered when the form is in the process of being closed, which causes all sorts of problems, so I unregister the form's event handler from framework's event source on Winforms thread like this:
var form = new SomeForm();
var src = new SomeDataSource();
// ...
src.OnFrameworkEvent += form.SomeAction;
form.Closing += (sender, eargs) => src.OnFrameworkEvent -= form.SomeAction;
Now, is this approach thread-safe? If the form is in the process of being closed, and a foreign thread calls BeginInvoke
, will the invocation still be queued for execution if the form is closed? (which means I still have a chance of encountering the same problem)
Is there a better approach or recommended pattern for cross-thread event handling?
No it is not. The thread might just be executing the event handler while you unregister it and close the form. Small odds, but not zero. You have to have the thread stopped before you can close the form. If you don't want to abort it, you'll have to keep the form open by canceling the FormClosing event, then let the thread's completion callback close the form.
Check this thread for more info.
You can add this code to constructor CheckForIllegalCrossThreadCalls = false;
and no exception will be thrown.
I haven't used a framework with its own event dispatcher, but I had my own experience with the threads that I created. Here's my experience
This approach is not thread-safe. The invocation will still be called even if the program itself is closed. I saw this in task manager (after the program is closed as you say) as hanging threads. (even if you kill the program from task manager also.). I had to kill those threads seperately later.
When the form is closing you have to kill the dispatcher thread so that it does not hang if anything wrong happens in that thread.
form.Closing += (sender, eargs) => src.OnFrameworkEvent -= form.SomeAction;
// pseudo-code (find c# equivalent)
if (dispatcherthread.isrunning)
dispatcherThread.kill();
上一篇: C#事件处理单线程应用程序
下一篇: C#中的线程事件处理