A Generic IAsyncResult Implementation


Lately, I’ve found myself writing implementations of IAsyncResult more than once, and as it turns out, all of those implementations have been so similar that I have ended up creating a generic implementation.


When implementing the Async Pattern, you can often get by with using a delegate as described in the design guidelines, and in this case, you don’t need to implement IAsyncResult yourself. However, there will be cases where a custom implementation of IAsyncResult may be necessary. In some cases, the folllowing class may be suitable to your needs.


Update: Oleg Mikhailik has been so kind to point out some flaws of the code I first posted (see the comments), so I’ve decided to update the post with a new version of the code. Again, whether such an implementation is suitable for you depends on your needs. The main point of this post is give an example implementation of IAsyncResult, since so few are available, so this is not an authoritative, general-purpose implementation.


internal class AsyncResult<T> : IAsyncResult, IDisposable
{
    private readonly AsyncCallback callback_;
    private bool completed_;
    private bool completedSynchronously_;
    private readonly object asyncState_;
    private readonly ManualResetEvent waitHandle_;
    private T result_;
    private Exception e_;
    private readonly object syncRoot_;
 
    internal AsyncResult(AsyncCallback cb, object state)
        : this(cb, state, false)
    {
    }
 
    internal AsyncResult(AsyncCallback cb, object state,
        bool completed)
    {
        this.callback_ = cb;
        this.asyncState_ = state;
        this.completed_ = completed;
        this.completedSynchronously_ = completed;
 
        this.waitHandle_ = new ManualResetEvent(false);
        this.syncRoot_ = new object();
    }
 
    #region IAsyncResult Members
 
    public object AsyncState
    {
        get { return this.asyncState_; }
    }
 
    public WaitHandle AsyncWaitHandle
    {
        get { return this.waitHandle_; }
    }
 
    public bool CompletedSynchronously
    {
        get 
        {
            lock (this.syncRoot_)
            {
                return this.completedSynchronously_;
            }
        }
    }
 
    public bool IsCompleted
    {
        get 
        {
            lock (this.syncRoot_)
            {
                return this.completed_;
            }
        }
    }
 
    #endregion
 
    #region IDisposable Members
 
    public void Dispose()
    {
        this.Dispose(true);
        GC.SuppressFinalize(this);
    }
 
    #endregion
 
    protected virtual void Dispose(bool disposing)
    {
        if (disposing)
        {
            lock (this.syncRoot_)
            {
                if (this.waitHandle_ != null)
                {
                    ((IDisposable)this.waitHandle_).Dispose();
                }
            }
        }
    }
 
    internal Exception Exception
    {
        get
        {
            lock (this.syncRoot_)
            {
                return this.e_;
            }
        }
    }
 
    internal T Result
    {
        get 
        {
            lock (this.syncRoot_)
            {
                return this.result_;
            }
        }
    }
 
    internal void Complete(T result,
        bool completedSynchronously)
    {
        lock (this.syncRoot_)
        {
            this.completed_ = true;
            this.completedSynchronously_ =
                completedSynchronously;
            this.result_ = result;
        }
 
        this.SignalCompletion();
    }
 
    internal void HandleException(Exception e,
        bool completedSynchronously)
    {
        lock (this.syncRoot_)
        {
            this.completed_ = true;
            this.completedSynchronously_ =
                completedSynchronously;
            this.e_ = e;
        }
 
        this.SignalCompletion();
    }
 
    private void SignalCompletion()
    {
        this.waitHandle_.Set();
 
        ThreadPool.QueueUserWorkItem(new WaitCallback(this.InvokeCallback));
    }
 
    private void InvokeCallback(object state)
    {
        if (this.callback_ != null)
        {
            this.callback_(this);
        }
    }
}

As reproduced here, you may have noticed that the class is internal. This is because I usually just copy in this code and use it internally, but if you want to include it in a reusable library, you will obviously need to change the class and relevant members (the constructors, Result and Complete) to public.


When implementing the Async Pattern, you can create and return an instance of AsyncResult<T> and return it from your BeginX method. Then, when your asynchronous operation completes, call the Complete method, which will store the result, release the WaitHandle and invoke any callback supplied by the client. To implement the EndX method, cast the incoming IAsyncResult to AsyncResult<T>, call WaitOne on its AsyncWaitHandle and return its Result property.


This is not the only way to implement IAsyncResult, but it has worked well for me in several cases.

Comments (19)

  1. mihailik says:

    The most problem here is AsyncWaitHandle. You are creating it even if it might not be used at all.

    And not only might, but it most likely will not be used — the common scenario for IAsyncResult is to fire BeginSomething and then either hope for AsyncCallback to be called, or call EndSomething wich itself blocks.

    Considering asynchronous design pattern may be used in performance-sensitive server-based application, you are effectively creating major resource bottleneck. And the only hope is that memory pressure will be high as well, so GC will cleanup all those bazillions of redundant ManualResetEvents.

    Recently ago I wrote couple of my own AsyncResult implementations for blocking queue thing, at it actually is VERY VERY non-trivial task.

    The key idea to deal with AsyncWaitHandle is to create it on-demand.

    The other problem (minor or major depends on the usage of the class) is thread safety. Although full thread safety requirement is not claimed, we definitely cannot be completely non-safe. Changing the completed/incompleted state shall be thread-safe in any case.

    I started my class with same design aproach — generic AsyncResult which holds result and can be used either for synchronous or asynchronous operation (CompletedSynchronously). But it proved to be extermely error-prone path. At the end I’ve got 2 separate classes, one for synchronously completed operation and one for asynchronously. Synchronously completed operation can be optimised even more aggressive, but the actual goal was not optimisation but clean and safe code.

    And one another time, think about thread safety and synchronisation. This cost cannot be passed to QA, it shall be thought through very accurately.

    P.S. I am planning to finish with my blocking queue class and enclosing project soon and the code will be posted for public use. But I can send it to any interesting party for review or direct use, without any restrictions.

  2. ploeh says:

    Hi Mihailik

    Thank you for your comment. I think it only demonstrates that my way isn’t the only way to do it 🙂

    As it is right now, the class is internal, so it assumes that you use it together with at least one other, public class. If you were to change it to an entirely public class, I agree that more robustness may be required.

    Your point about WaitHandle resource usage is valid: It just occurred to me that WaitHandle implements IDisposable, so that should have clued me in on the fact that I should be more conservative about its usage. Incidentally, since AsyncResult<T> has an IDisposable member variable, it should itself implement IDisposable.

    At least, this issue should be easy to resolve by implementing the AsyncWaitHandle with lazy initialization, and updating the Complete method accordingly.

    I think you are right about the need for thread-safety around at least some of the member variables. I’ll see what I can do about that 🙂

    It may be that this implementation of IAsyncResult is not useful in all cases, but then I never claimed that. On the other hand, it has served me well on several occasions. My main motivation for posting this (and thus, sticking my neck out) was that it’s actually pretty difficult to find an example implementation of IAsyncResult.

  3. greg says:

    HI..

    Im quite interested in seeing how this IAsyncResult would be used in a project.. Im currently implementing my own BeginXXX EndXXX methods and inside i use delgate.beginInvoke with call backs etc.. can this custom IAsyncResult be used with the Delegate.Invoke model? or is it used differently.. Any same projects would be greatly appreciated.  I’m guessing this would be used with a ThreapStart or something along those lines?

  4. ploeh says:

    Hi Greg

    Thank you for writing. As I wrote in the introduction to my post, you don’t need to write a custom implementation of IAsyncResult if you use the delegate approach.

    In this case, delegate.BeginInvoke returns an IAsyncResult implementation that you should be able to reuse in your own implementation.

    HTH

  5. mrhaboobi says:

    Hi Again.

    I’ve now completed my delegate approach, and as you mentioned a custom iasyncresult is not possible.  Do you have an example using this Generic Iasycn for people that take the Threading approach.. Im going to need to develop some async web services/ handlers and from what i hav found a custom iasyncresult combined with threads is the best way?  im just looking for a tidy implementation example 🙂

    Cheers

  6. ploeh says:

    Hi mrhaboobi

    Thank you for writing. I’m not sure I understand your need, but maybe this article can help answer some of your questions: http://msdn2.microsoft.com/en-us/library/83bkx91t.aspx

    If this doesn’t help, you are welcome to write again and explain what you are trying to do.

  7. Jakob says:

    You probably already know but Jeffrey Richter has published his generic implementation of IAsyncResult in his Concurrent Affairs column in the March issue of MSDN Magazine: http://msdn.microsoft.com/msdnmag/issues/07/03/ConcurrentAffairs/

    Best regards, Jakob.

  8. ploeh says:

    Hi Jakob

    Yes, someone else was so nice to point that out to me, but in my defense, that article wasn’t published when I wrote my post.

    I haven’t yet had a chance to read the article, but I’m sure Jeffrey Richter’s implementation is much better and more correct than mine 🙂

  9. Ho trovato questo post sui blogs di MSDN. Fornisce un modello generico di IAsyncResult che in effetti

  10. bonbon says:

    I read Jeffrey Richter’s implementation, but I don’t think it is as useful as yours. Nice job, thx a lot.

  11. ploeh says:

    Hi bonbon

    Thank you for your praise, but after having read Jeffrey Richter’s article, I suspect that his implementation is more lightweight and robust than mine 🙂

  12. Malcolm Hall says:

    dude the first thing you should explain is what this code is for. I was googling for something and your code made no sense to me.

  13. reisi says:

    Nice looking implementation.. Just why isn’t this class included in .NET as a public built-in abstract base class for everyone to use?

    There must be some base class for implementing IAsyncResult classes; it wouldn’t make any sense if every async method in .NET would have their own..

  14. ploeh says:

    Hi reisi

    There are no base classes in the BCL for implementing IAsyncResult, but an implementation like Jeffrey Richter’s (see comments above) would be a very good candidate.

    You can suggest such a class on https://connect.microsoft.com/VisualStudio.

  15. esskar says:

    I think you should check the return value of ThreadPool.QueueUserWorkItem and throw an exception if it returns false.

  16. Chris says:

    So when exactly do you intend for your IAsyncResult object to be disposed?

  17. Erik Rogers says:

    Nice helpful piece!

    Just to nitpick, you should add a private member variable bool "disposed". You should check that it is not already disposed before disposing for safety.

    if(disposed)

      return;

    // dispose code here

    disposed = true;

  18. RandomEngy says:

    This is incorrect if someone calls Complete(x, true). You'll report CompletedSynchronously as true but you're actually calling the callback on a Threadpool thread, which means it will have completed asynchronously for people registered to the callback.

Skip to main content