What is the proper technique to have ThreadA signal ThreadB of some event, without having ThreadB sit blocked waiting for an event to happen?
i have a background thread that will be filling a shared List<T>. i'm trying to find a way to asynchronously signal the "main" thread that there is data available to be picked up.
i considered setting an event with an EventWaitHandle object, but i can't have my main thread sitting at an Event.WaitOne().
i considered having a delegate callback, but a) i don't want the main thread doing work in the delegate: the thread needs to get back to work adding more stuff - i don't want it waiting while the delegate executes, and b) the delegate needs to be marshalled onto the main thread, but i'm not running a UI, i have no Control to .Invoke the delegate against.
i considered have a delegate callback that simply starts a zero interval System.Windows.Forms.Timer (with thread access to the timer synchronized). This way the thread only needs to be stuck as it calls
Timer.Enabled = true;
but that seems like a hack.
In the olden days my object would have created a hidden window and had the thread post messages to that hidden windows' HWND. i considered creating a hidden control, but i gather that you cannot .Invoke on a control with no handle created. Plus, i have no UI: my object could have been created on a web-server, service, or console, i don't want there to be a graphical control appearing - nor do i want to compile a dependency on System.Windows.Forms.
i considered having my object expose an ISynchronizeInvoke interface, but then i would need to implement .Invoke(), and that's my problem.
What is the proper technique to have thread A signal thread B of some event, without having thread B sit blocked waiting for an event to happen?
Here's a code sample for the System.ComponentModel.BackgroundWorker class.
If you use a backgroundworker to start the second thread and use the ProgressChanged event to notify the other thread that data is ready. Other events are available as well. THis MSDN article should get you started.
I'm combining a few responses here.
The ideal situation uses a thread-safe flag such as an
AutoResetEvent
. You don't have to block indefinitely when you callWaitOne()
, in fact it has an overload that allows you to specify a timeout. This overload returnsfalse
if the flag was not set during the interval.A
Queue
is a more ideal structure for a producer/consumer relationship, but you can mimic it if your requirements are forcing you to use aList
. The major difference is you're going to have to ensure your consumer locks access to the collection while it's extracting items; the safest thing is to probably use theCopyTo
method to copy all elements to an array, then release the lock. Of course, ensure your producer won't try to update theList
while the lock is held.Here's a simple C# console application that demonstrates how this might be implemented. If you play around with the timing intervals you can cause various things to happen; in this particular configuration I was trying to have the producer generate multiple items before the consumer checks for items.
If you don't want to block the producer at all, it's a little more tricky. In this case, I'd suggest making the producer its own class with both a private and a public buffer and a public
AutoResetEvent
. The producer will by default store items in the private buffer, then try to write them to the public buffer. When the consumer is working with the public buffer, it resets the flag on the producer object. Before the producer tries to move items from the private buffer to the public buffer, it checks this flag and only copies items when the consumer isn't working on it.You can use an AutoResetEvent (or ManualResetEvent). If you use AutoResetEvent.WaitOne(0, false), it will not block. For example:
If your "main" thread is the Windows message pump (GUI) thread, then you can poll using a Forms.Timer - tune the timer interval according to how quickly you need to have your GUI thread 'notice' the data from the worker thread.
Remember to synchronize access to the shared
List<>
if you are going to useforeach
, to avoidCollectionModified
exceptions.I use this technique for all the market-data-driven GUI updates in a real-time trading application, and it works very well.
There are many ways to do this, depending upon exactly what you want to do. A producer/consumer queue is probably what you want. For an excellent in-depth look into threads, see the chapter on Threading (available online) from the excellent book C# 3.0 in a Nutshell.