views:

102

answers:

3

Hi, I am writing a Windows Form application. It has a thread to perform some operation and when the operation found something it has to notify the main form to change a control.

Currently the notification uses the C# event hadling described in the following MSDN page: http://msdn.microsoft.com/en-us/library/wkzf914z(VS.71).aspx

But I am not sure about the delegate. Since in the situation I described above the thread invokes the delegate. Is this a thread safe approach to raise the event?

Is it better to implement Windows Messages (SendMessage) in C# and then implement the message handler in the WindowProc.

Appreciate you time on this.

+3  A: 

Unless you need very fine control over the threading, you can probably use BackgroundWorker instead. It handles all of the cross-thread communication for you. You basically put your background code in its DoWork event handler and then pass data back to the UI thread via its ProgressChanged and RunWorkerCompleted events. The link above has a complete example of how to use it.

But in general, simply adding event handlers and raising events is thread-safe as long as you follow some basic guidelines. However, the event handler will be called on the same thread as the code that raises the event. The event handling code may not be expecting to be called on a background thread so that's where BackgroundWorker comes in handy.

The following is a very basic skeleton of a class that raises an event in a thread-safe way. Whether the code that handles the event is thread-safe is another matter entirely.

class MyClass {

    public event EventHandler SomethingHappened;

    protected virtual void OnSomethingHappened(EventArgs e) {
        EventHandler handler = SomethingHappened;
        if (handler != null) {
            handler(this, e);
        }
    }

    public void DoSomething() {
        OnSomethingHappened(EventArgs.Empty);
    }

}
Josh Einstein
Hi Josh,Thank you for your reply.Is it better to implement Windows Messages (SendMessage) in C# and then implement the message handler in the WindowProc?Please let me know.Thanks again.
HJ
No, that is not necessary in .NET. There are much better ways of posting calls to the UI thread. One of them is BackgroundWorker which internally uses a class called SynchronizationContext. Another way is to use the BeginInvoke method of any control. The Windows Forms infrastructure hides all of the WndProc goo from you. If you resort to using it directly then you'll be re-implementing a lot of what you get for free.
Josh Einstein
A: 

Try to use InvokeRequired / Invoke on UI controls. It's better to avoid raw windows message queuing.

Andrew Florko
A: 

The delegate approach isn't all that bad, but the problem is that the event invokes the event handlers in the other thread. That foxes your UI update, which needs to be done in the main thread. So you can use InvokeRequired appropriately in the event handler.

void OnStatusMessage(string s)
{
  // might be coming from a different thread
  if (txtStatus.InvokeRequired)
  {
    this.BeginInvoke(new MethodInvoker(delegate()
    {
      OnStatusMessage(s);
    }));
  }
  else
  {
    StatusBox.Text += s + "\r\n";
    StatusBox.SelectionStart = txtStatus.TextLength;
    StatusBox.ScrollToCaret();
  }
}

This may not be required when using BackgroundWorker as Josh mentioned. But it's useful if you're considering ThreadPool and WaitCallBack(*) to manage threads.

An issue with using Windows messages is that you have to know which window to send messages to, and multiple subscribers is more painful. (For events you just have to += another handler)

  • I amn't able to post a hyperlink for WaitCallBack because I don't have multi-link pedigree yet.
Deepak Shenoy