stic
stic

Reputation: 1028

How to make sure that a thread is awaiting for events?

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

Answers (2)

Kiril
Kiril

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

stic
stic

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

Related Questions