Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to parallelize event handler execution in C#

I have a Kinect device and I am developing a program with it by using C#.

In order to manage the device, I have used AllFramesReady event in order to process the depth and color information.

I have created an event handler to process the data which is named EventHandler1. I am doing a lot of processing inside this event handler.

I would like to do some more computation inside a second event handler named EventHandler2.

Is it possible to run this 2 event handlers which are basically 2 functions on parallel, on 2 different threads of the main process? If possible, could you please give me a sample code for doing this?

like image 878
Simon Avatar asked Oct 07 '22 23:10

Simon


1 Answers

This is easy enough to wrap up in a class; however, you need to aggregate all the event handlers into a single event handler before subscribing to the desired event.

Here is a quick-and-dirty class to demonstrate this. The first event provided runs inline with the event call while all others are executed on the default thread pool.

class ParallelEvent<TEventArg> where TEventArg : EventArgs
{
    private readonly EventHandler<TEventArg> _handler1;
    private readonly EventHandler<TEventArg>[] _moreHandlers;

    public ParallelEvent(EventHandler<TEventArg> handler1, params EventHandler<TEventArg>[] moreHandlers)
    {
        if (handler1 == null)
            throw new ArgumentNullException("handler1");
        if (moreHandlers == null)
            throw new ArgumentNullException("moreHandlers");
        _handler1 = handler1;
        _moreHandlers = moreHandlers;
    }

    public void Handler(Object sender, TEventArg args)
    {
        IAsyncResult[] asyncResults = new IAsyncResult[_moreHandlers.Length];
        for (int i = 0; i < _moreHandlers.Length; i++)
            asyncResults[i] = _moreHandlers[i].BeginInvoke(sender, args, null, null);

        _handler1(sender, args);

        for (int i = 0; i < _moreHandlers.Length; i++)
            _moreHandlers[i].EndInvoke(asyncResults[i]);
    }
}

Now to use this we construct a ParallelEvent class providing it all the event handlers we want to run in parallel. Then we subscribe to the event 'test' with the class's Handler method. Finally we call the event 'test' and review the output. Consider the following example:

private static event EventHandler<EventArgs> test;

static void Main()
{
    var e = new ParallelEvent<EventArgs>(Test1, Test2);
    test += e.Handler;
    test(null, EventArgs.Empty);
}

static void Test1(Object sender, EventArgs args)
{
    Console.WriteLine("Start Test 1");
    Thread.Sleep(100);
    Console.WriteLine("End Test 1");
}

static void Test2(Object sender, EventArgs args)
{
    Console.WriteLine("Start Test 2");
    Thread.Sleep(100);
    Console.WriteLine("End Test 2");
}

As expected the program above runs them in parallel as demonstrated by the following output:

Start Test 1
Start Test 2
End Test 2
End Test 1

Lastly you need to be aware of other concerns regarding multi-threaded code. Any shared state being changed now needs to be synchronized, etc.

With a little work you could adapt the above class to expose an event so that listeners can subscribe and unsubscribe at will. Then in the Handler method you would extract the delegate list via Delgate.GetInvocationList(). Once you have a list of delegates you can process them the same as the existing Handler method above.

like image 53
csharptest.net Avatar answered Oct 12 '22 10:10

csharptest.net