Reputation: 1028
I wonder how to make sure that a thread is awaiting for events. Let say I've a component that raises events:
public delegate void TestHandler(object sender, EventArgs eventArgs);
class Producer
{
public event TestHandler Handler;
public void InvokeHandler(EventArgs eventargs)
{
var handler = Handler;
if (handler != null) handler(this, eventargs);
}
public Producer()
{
Task.Factory.StartNew(() =>
{
while (true)
{
Thread.Sleep( (new Random()).Next(0,100) );
InvokeHandler(new EventArgs());
} }); } }
And a Listener:
class Listener
{
private readonly BlockingCollection<EventArgs> _blockingCollection;
public Listener()
{
var producer = new Producer();
_blockingCollection = new BlockingCollection<EventArgs>(10);
producer.Handler += producer_Handler;
}
void producer_Handler(object sender, EventArgs eventArgs)
{
_blockingCollection.TryAdd(eventArgs); //no error handling for simplicity sake
}
internal void ProcessEvents()
{
while (true)
{
EventArgs eventArgs;
try
{
if (_blockingCollection.TryTake(out eventArgs))
Console.WriteLine("Received event");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
} } } }
If I would start it as:
class Program
{
static void Main(string[] args)
{
var listner = new Listener();
listner.ProcessEvents();
} }
I got expected behaviour (from time to time I'm getting the event through blocking collection.
However if I would wrap this call in Task:
Task.Factory.StartNew(() => {
var listner = new Listener();
listner.ProcessEvents(); });
I will never got into the processing part. Any idea why it would be? Do I miss something obvious?
On the side, does someone know a good description of a pattern that will help here? I'm looking to pick-up events on one thread (preferably not the main application thread), then process them on a separate thread at the same time blocking if the number of events is getting too high (typical thresholdingI assume)
Thanks in advance,
Upvotes: 0
Views: 231
Reputation: 40395
In order to figure out what's going on you should put some logging messages and verify that no exceptions are thrown when when you start the new task:
Thread listenerThread = new Thread(() =>
{
// print a message when the task is started
Console.WriteLine("Task started!");
var listner = new Listener();
listner.ProcessEvents();
});
// set your thread to background so it doesn't live on
// even after you're
listenerThread.IsBackground = true;
listenerThread.Start();
Thread.Join() does the same thing as Task.Wait(). You can call it without specifying a timeout, you can specify an infinite timeout or if you want your test to stop waiting for the thread to finish, then you specify a timeout in milliseconds:
// this will block until the thread is complete
listenerThread.Join(Timeout.Infinite);
If you need to stop the test, then you have to perform an asynchronous interrupt. Interrupt raises a ThreadInterruptedException
inside the Thread
which you're supposed to catch (as shown in the ProcessEvents
method):
listenerThread.Interrupt();
Additionally, you're using a blocking collection, but you're not utilizing the blocking functionality of the collection. There is no reason why you should keep retrying when there is nothing in the collection, instead you would rather block until there is something in it (which is what this collection is designed to do):
internal void ProcessEvents()
{
while (true)
{
try
{
var myEvent = _blockingCollection.Take();
Console.WriteLine("Received event");
}
catch(ThreadInterruptedException)
{
Console.WriteLine("Thread interrupted!");
break;// break out of the loop!
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
// Do you REALLY want to keep going if there is an unexpected exception?
// Consider breaking out of the loop...
}
}
}
Upvotes: 0
Reputation: 1028
Stupid me...
When I wrap my call in Task it is run on a Background thread. I should have wait for the task to finish before quiting.
Having done that, that is assigning:
var task = Task.Factory.StartNew(/*task body*/);
task.Wait();
and waiting I have got what I want.
Upvotes: 1