views:

6557

answers:

6

I have a class containing a worker thread which receives data from a queue in a loop.

Another part of the app sinks an event from this class, which the class raises for each queue item.

These events are fired asynchronously, so at busy times the other part of the app can be processing several events at once.

This should be fine but we've discovered a scenario where this can cause problems.

We need a quick solution while the main issue gets addressed. Does the framework provide a simple way I can force the worker thread to wait while each event gets processed (so they are processed sequentially)? If not, what's the easiest way to implement this?

A: 

There is no general way.

In the end the handlers need to provide a mechanism for tracking.

If you are using BeginInvoke, rather than raising the events directly, you can use a wrapper, within which you call the real event handler synchronously, then raise the wrapper asynchronously. The wrapper can maintain a counter (with Interlocked operations) or set an event as meets your needs.

Something like:

TheDelegate realHandler = theEvent;
var outer = this;
ThreadPool.QuereUserWorkItem(x => {
  // Set start of handler
  realHandler(outer, eventArgs);
  // Set handler finished
};
Richard
A: 

All of the event handlers sinking events raised by the queue-reading worker thread are called in the queue-reading worker thread. As long as the event handlers aren't spawning threads of their own, you should be able to wait for the event handlers to finish by calling Thread.Join() on the queue-reading worker thread.

Jekke
A: 

My guess is that you want to simply go away from triggering the action by raising an event and calling the method directly.

AFAIK events are going to be async and I am not aware of any "easy" ways of changing that.

Mitchel Sellers
+1  A: 

The ManualResetEvent class might help you here, unless I'm not understanding your question. You can use it to block the firing of the next event until the last one completes.

lc
+3  A: 

A simple answer would be to lock() on a single object in the event handler. All of the theads would wait to get the lock.

Thanks Eric. I think I'll do that.
rc1
A: 

Turns out there's another answer. You can just add the following attribute to the method.

[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.Synchronized)]