views:

571

answers:

2

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;
  1. 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)

  2. Is there a better approach or recommended pattern for cross-thread event handling?

+1  A: 

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

  1. 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.

  2. 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();
    
Aykut
What if the dispatcher thread needs to remain alive to handle other Winforms?
Jon B
I am afraid it is the case. I have multiple forms listening to the same event source.
Alex B
If I correctly understand what you're saying, then setting the thread's IsBackground property to true will prevent hanging threads.
ebpower
+3  A: 

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.

Hans Passant
I like this approach. I like using callback methods for signaling when a thread is done.
ebpower