Multithreading: implementing the event based pattern

In the last post of the series, we’ve taken a look at the main features offered by the event based pattern. Today, we’re going to look at how we can implement that pattern. We’re going to start small and we’re going to reuse the IAsyncResult sample for showing how you can implement this pattern.

As we’ve seen in the previous post, we need to (at least) add a method (named XXXAsync) that will start the asynchronous operation and an event (named XXXCompleted) that will fire . In practice, this means that we need something like this:

class DoSomeWork {
    public Boolean IsPrimeNumber(Int32 number) {
        /* same as before*/
    }
    public event EventHandler<PrimeNumberVerificationCompletedEventArgs> PrimeNumberCompleted;
    protected void OnPrimeNumberCompleted( PrimeNumberVerificationCompletedEventArgs evtArgs ){
        if (PrimeNumberCompleted != null) {
            PrimeNumberCompleted(this, evtArgs);
        }
    }
    public void IsPrimeAsync(Int32 number) {
     //some code here…
    }
}

As you can see, we’ve got a PrimeNumberVerificationCompletedEventArgs that is passed back. As we’ve said, this must be a AsyncCompletedEventArgs (or derived) class. In this case, we need to return a value, so we’ll need to create a new derived class which I called PrimeNumberVerificationCompletedEventArgs. Here’s the code for that class:

public class PrimeNumberVerificationCompletedEventArgs: AsyncCompletedEventArgs {
    private readonly Int32 _testedNumber;
    private readonly Boolean _isPrime;
    internal PrimeNumberVerificationCompletedEventArgs( Int32 testedNumber,
        Boolean isPrime,
        Exception exception,
        Boolean calculationCanceled,
        Object state )
        : base(exception, calculationCanceled, state) {
        _testedNumber = testedNumber;
        _isPrime = isPrime;
    }
    public Int32 TestedNumber {
        get{
            RaiseExceptionIfNecessary();
            return _testedNumber;
        }
    }
    public Boolean IsPrime{
        get{
            RaiseExceptionIfNecessary();
            return _isPrime;
        }
    }
}

As you can see, I’ve added two properties to the base class: TestedNumber (returns the number that was passed to the IsPrimeAsync method) and IsPrime (returns the result of the processing). As you can see, both properties call the RaiseExceptionIfNecessary method before returning the value back to the client. Internally, this method will throw the exception (when it isn’t null) that supposedly originated during the asynchronous operation and that was passed to the constructor.

As you might expect, most of the action happens on the IsPrimeAsync method. From within that method, we need to start the processing on a different thread. For starters, we’re allowing only one asynchronous call at the time. Here’s a possible implementation for the IsPrimeAsync method:

public void IsPrimeAsync(Int32 number) {
    if (_isRunning) {
        throw new InvalidOperationException();
    }
    _isRunning = true;
    _currentOperation = AsyncOperationManager.CreateOperation(null);
    ThreadPool.QueueUserWorkItem(state =>
                    {
                        var numberToCheck = (Int32)number;
                        var isPrime = false;
                        Exception throwException = null;
                        try {
                            if (number > 2) {
                                isPrime = true;
                                var half = number / 2;
                                for (var i = 2; i < half; i++) {
                                    if (number % i == 0) {
                                        isPrime = false;
                                        break;
                                    }
                                }                               
  

                          }
                        }
                        catch (Exception ex) {
                            throwException = ex;
                        }
                        finally {
                            NotifyEndOfOperation(numberToCheck, isPrime, false, throwException);
                        }

                    }, number);
}

There are a couple of interesting points here:

  • we start by creating an AsyncOperation instance (_currentOperation is a field of the class) by using the helper AsyncOperationManager class. As you’ll see, this class handles most of the work for us and I’ll have much more to say about it in future posts (I guess that when I finish this topic, I’ll go straight into GUI and multithreading);
  • we use an auxiliary field (_isRunning) which is signaled when we start a new operation. Since this first version does not support more than one asynchronous call at a time, we end up throwing an exception whenever the method is called before it ends the “current” running asynchronous operation;
  • we need to wrap our code in a try/catch block so that we catch all the exceptions that might happen during the execution of that code (this is not without its problems – what to do with an out of memory exception? – but it ensures that a less “critical” exception doesn’t crash the process). Notice that eventual exceptions are saved on local field so that they can be passed to the client of the event.

The NotifyEndOfOperation method is responsible for “firing“ the event back on the thread that started the request (which is really needed when you’re writing code for GUIs). To do that, it must first pack all the info into a PrimeNumberVerificationEventsArg expected by the consumer of the API. As you’ll see, the method ends up being really simple because we end up relying once again on the “mysterious” AsyncOperation class:

private void NotifyEndOfOperation( Int32 numberToTest,
                Boolean isPrime,
                Boolean cancelled,
                Exception thrownException ){
  var evt = new PrimeNumberVerificationCompletedEventArgs(
                                numberToTest,
                                isPrime,
                                thrownException,
                                cancelled,
                                null);
  _currentOperation.PostOperationCompleted(
           state => {
              _isRunning = false;
              OnPrimeNumberCompleted((PrimeNumberVerificationCompletedEventArgs)state);
           },
           evt);
}

As I’ve said before, we’ll spend a couple of posts on GUIs and asynchronous processing. Until then, just know that calling this method signals the end of an asynchronous operation (notice also that this means that you cannot make future calls over this AsyncOperation instance). From within the delegate we pass to the method, we turn off our running flag and fire the event by calling the auxiliary OnPrimeNumberCompleted method:

protected void OnPrimeNumberCompleted( PrimeNumberVerificationCompletedEventArgs evtArgs ){
    if (PrimeNumberCompleted != null) {
        PrimeNumberCompleted(this, evtArgs);
    }
}

And now that we’ve got the class ready, here’s how you’re expected to use it:

var work = new DoSomeWork();
work.PrimeNumberCompleted += (sender, e ) => {
                                 Console.WriteLine(e.IsPrime); evt.Set();
                             };
work.IsPrimeAsync(19);

There still more to say about this pattern, so we’ll return to it in future posts. Keep tuned!

~ by Luis Abreu on June 17, 2009.

38 Responses to “Multithreading: implementing the event based pattern”

  1. ??? ???????????? ?????? ???????? ???-???????,? ????????? ?????,?????????? ????-??????, 50 ???????.
    ??? ??????? ? ???????????? ???????? ???????????? ????????? ???????????? ? ????????
    ?????????.
    ??????? ???????????? ????? ??????? ?????? ? ???? ?????.
    ???????????? ?? ??????? ?????? ?????? ?????????? ??? ???????????????!
    ?? ????????? ?? ????? ?????????????? ????? ???? ?????????, ? ???? ????????????? ?????? ???????.
    ???????????? ? ????????? ?????.
    ??????? ? ??????? ????????? ????? ???? 16-???.
    ??????? ???????, ??????, ??????????, ? ???????? ????? ??????? ?? ?????????????.
    ??? ??????? ?????????? ????????? : Skype/????? ??? ???????/ ICQ .
    ?????????????? ????????????? – ???????? ?? ?????.

    ?????? ???????? ?? ??.????? webp2010@gmail.com

  2. LDjlzh Great site. Good info.

  3. Can you explain how to handle the scenario where the callbacks generation speed of the async event class is greater than the consuming thread (console based application where no queuing mechanism is implemented by default). Currently I am locking the consuming thread using lock(this){ event handler } to solve this issue. Is this a valid approach? Or the event based asynchronous model is not valid approach in this scenario?

    Regards

  4. Hello.

    I”m not following you. can you be a lilttle more specific please? thanks.

  5. I need to develop a network application that consists of two modules. One need to handle the clients, i.e., send/receive requests/data from clients and the other module need to handle the business logic for different requests. Now I want to execute the clients management module in a separate thread and generate events in response of clients requests. The other module that implements the business logic will subscribe to these events and perform corresponding actions in response to the events raised. Now the problem is if an event is raised from client management module and business logic layer is executing the request. Mean while if another event is raised, current event is interrupted and the new event starts executing. So I need a solution to avoid this problem. One way is to implement my own queue management system that queues events when raised and forward to business layer when it becomes idle. So my question is should I use event based pattern in this scenario or it is not suitable in this case? If yes i should use, then what about the problem i have mentioned, how to handle it?

  6. I”d say no. the event pattern should be used essentially in UI scenarios, where you need to make sure that the callback method is executed back in the some thread which started the async call. it looks like this is not the scenario you”ve got, so I”d say you won”t be gaining much from using it.

    btw, i”m still not sure in what”s the problem you”re facing when receiving a new event. are you saying that you can”t just have another thread do something if currently there”s a business action going on as a result of a previous event?

  7. Yes, if the thread that have registered events of the asyncmethod is busy in executing business actions of an event and meanwhile another event is raised from the asyncmethod, that stops the previous event and starts the new event business execution.

    So if I don”t use this pattern then how to achieve event driven programming in a multi-threaded application?

  8. Wouldn”t you be better by using some sort of compensation mechanism instead of enforcing “real time” handling of an action?

  9. Didn”t get your point. Can you elaborate it a bit? Thanks

  10. Sorry for the late reply, but i”ve been a little busy.

    please disregard my last comment because i didn”t understand the question…

    I”m still not sure if you want to 1.) stop the current processing when the a new event arrives or 2.) you don”t want to stop the current processing when another event arrives.

    if you want 2, then you can use a collection where you have producers and consumers (ie, you can have several threads putting stuff there and others removing). I think I”ve written a post on it a long time ago…

    if it”s 2, then you”ll have to keep looking for new objects in the queue. when it”s there you”ll have to stop the current action (probably use some sort of compensation for cancelling it before starting the new one?)

  11. ?????? ??????????? ???????? ????????? ????? ?????? ? ??????.
    ??????? ????? ?? ?????? ???????? ???????!
    http://icetv.ru

    http://icetv.ru/ice0.gif%5D

  12. ?????????? ????????? ? ??? ???????????. ???????? ?????, ?????? ????????.
    http://icetv.ru

    http://icetv.ru/ice0.gif%5D

  13. ??????? ? ??? ???????????? ??????????? ??????????? Windows XP, Office 2007, Server 2008 ? ?????? ???????????? ??????????? ???????? ?? ??????? ?????!
    ??????????? ?? ?-???? softforme@bk.ru

  14. ????? ? ??? ???????????? ?? Windows, Office, Server ? ?????? ???????????? ??????????? ??????????? ?? ??????? ?????!
    ??????????? ?? ?-???? softforme@bk.ru

  15. ??????? ? ??? ???????????? ?? Windows XP, Office 2007, Server 2008 ? ?????? ???????????? ??????????? ??????????? ?? ??????? ?????!
    ??????????? ?? ?-???? softovichok@mail.ru

  16. ????? ? ??? ???????????? ??????????? ??????????? Windows XP, Office 2007, Server 2008 ? ?????? ???????????? ??????????? ???????? ?? ??????? ?????!
    ??????????? ?? ?-???? softovichok@mail.ru

  17. ????????? ???????????? ???? Windows 2000/XP/VISTA/7, Office XP/2003/2007, Server 2003/2008 ? ?????? ???????????? ??????????? ???????? ?? ??????? ?????!
    ??????????? ?? ?-???? softovichok@mail.ru

  18. ?????????? ?????? ??????????? ??? ??????, ?? ?????, ??? ???????? ?? ?? ???????????, ??? ???????????? ? ????? ???????? ?????. ? ??? ??????? ??????? – ????? ???, ??????????, ????? ???????????? ????? http://sweetwear.ru/1200_b_1.php . ??? ?????????????? ???-?????? ???????????.

  19. ????? ? ?????? ????? ?????????? ? ??????, ?? ?????? ?? ??????-??????. ??? ?????????? ????? ? ????? ????????? ????? ? ??.
    ?????????? ?????????? ?? ????? 15 ?????. ?? ???? ???.

    ???? ????????:
    +38 048 795 28 95
    +38 098 8 777 333
    +38 063 8 555 333

  20. ????? ? ?????? ????? ?????????? ? ??????, ?? ?????? ?? ??????-??????. ??? ?????????? ????? ? ????? ????????? ????? ? ??.
    ?????????? ?????????? ?? ????? 15 ?????. ?? ???? ???.

    ???? ????????:
    +38 048 795 28 95
    +38 098 8 777 333
    +38 063 8 555 333

  21. this information is great to me!! thank you guys for your awesome posts As Nick says, iA?ll re-read it again, and again …

  22. ??? ?? ??????, ? ????? ???????? ????? ? ?????? ?????? ????? ?????????. ????? ?? ? ???????? ?????? ? ?????? ??????, ? ??? ????? ?????? ??? ???? ????????? ???????. ??????? ?? ???? ??????? ? ?????? ??? ????? ?? ?? ????, ? ?? ?????. ???? ????? ?? ? ???? ??????!

  23. ?????? ??? ??????????????? ??????? 18-30 ???
    ??????????? ?????????? ? ?.?????? ? ??????????? ??????????
    ?/? 150?.?. ? ????. 89653072078. http://allsexin.ru

  24. ????? ??????? ?????????? ??? ????????. ????? ?.?.??? ????? ??????? ???????????! ???????? ???????, ????. ???????? ??????? ????? ?? ?????? ????-??????. ??????? ???????! ?? ????? ??????? ?????? ???????? ?3.

  25. ?????? ??? ??????????????? ??????? 18-30 ???
    ??????????? ?????????? ? ?.?????? ? ??????????? ??????????
    ?/? 150?.?. ? ????. 89653072078. http://allsexin.ru

  26. ????? ??????? ?????????? ??? ????????. ????? ?.?.??? ????? ??????? ???????????! ???????? ???????, ????. ???????? ??????? ????? ?? ?????? ????-??????. ??????? ???????! ?? ????? ??????? ?????? ???????? ?3.

  27. ?????????????? ??????? ???????? ??? ???????????? ???????????? ? ????? ???????????!
    ????? ????????? ?????????? ????? ???????? ? ??????.
    http://alekandra.sitecity.ru/index.phtml

  28. ?????????????? ??????? ???????? ??? ???????????? ???????????? ? ????? ???????????!
    ????? ????????? ?????????? ????? ???????? ? ??????.
    http://alekandra.sitecity.ru/index.phtml

  29. ?????????? ??????????? ?? ???????, ?? ???. ?? ????? ?? ?? ???????? ???? ????? ??? ???????? ??? – 869728

  30. ??????? ????????? ????????! ????????? ??????? ???????? ?? ??????????? ???????????????? ? ???????????????. ? ????? ?? ????? ? ??????? ???? “????????? ????????”? ????? ???????? ??????????, ??? ??????????? ???? ???? – ??? ????????, ??? ?? ? ??? ?????.

  31. ?? ???????? ? ???????. ?????? ? ??? ???? 727503

  32. ????.. ??? ?????.

  33. ?????????? ?????? ?????????. ?????? ????? ???? ??????? ? ????? ??? ??????? ? ?????. ???????? http://myrealsex.ru

  34. ?????????????? ??????? ???????? ??? ???????????? ???????????? ? ????? ???????????!
    ????? ????????? ?????????? ????? ???????? ? ??????.
    http://alekandra.sitecity.ru/index.phtml

  35. ???????? ???????????? ??????????!

  36. ?????? ??? ??????????????? ??????? 18-30 ???
    ??????????? ?????????? ? ?.?????? ? ??????????? ??????????
    ?/? 150?.?. ? ????. 89653072078. http://allsexin.ru

  37. ?????? ??? ??????????????? ??????? 18-30 ???
    ??????????? ?????????? ? ?.?????? ? ??????????? ??????????
    ?/? 150?.?. ? ????. 89653072078. http://allsexin.ru

  38. ???????? ?????? ?????? ?? ????????????????
    http://getwork.cc – ?????? ??? ????????…

Leave a reply to Irfan Cancel reply