Do you have to call EndInvoke (or define a callback ) for asynchronous method calls even if you don't have anything to do when it returns

10,422

Solution 1

Yes, you have to call EndInvoke(). Not doing so causes a fairly nasty resource leak that lasts for 10 minutes. The underlying plumbing is .NET Remoting, 10 minutes is the, ahem, "default lifetime lease time". Do this often enough and your program will keel over. Having the delegate target take more than 10 minutes has interesting results too.

But most importantly, if not for the result of the invoked operation, you need to find out if the invoked method completed successfully. If it died on an exception then you will not find out about that until you call EndInvoke(). At which point the exception is re-raised. Actually handling that exception is fairly tricky since you don't really know how much of your program state got mutated by the delegate target before it exploded. It is pretty important that the target doesn't have too many side effects if you really want to catch it. Or conversely, that the target catches and rethrows the exception, performing state restoration as necessary.

The example you used is a pretty silly one of course, hard to come with doing anything useful between the BeginInvoke and EndInvoke calls in one method. You always rely on the callback that you can register, 2nd to last argument in the BeginInvoke call. Or in other words, don't pass null like the example code did. And favor classes like BackgroundWorker and Task, even ThreadPool.QueueUserWorkItem() to take the sting out of this code. Using a delegate's BeginInvoke() method is very low-level hacking.

Delegates are an enormously powerful abstraction in .NET but they didn't distribute its capabilities too well. Using them to implement events is boilerplate and trouble-free. Using its BeginInvoke() method properly is a black belt art. A notable detail is that it no longer works in .NETCore, support for remoting was removed from CoreCLR.

Solution 2

Before anything, these links might be of interest:

Calling Synchronous Methods Asynchronously

Is Delegate.EndInvoke() really necessary?


Now, about your questions:

Per the comment control is returned immediately to the calling code when it hits the BeginInvoke line.

Yes, the call is made asynchronously (I may assume it's using another thread).

Does that mean that the code that follows (EndInvoke followed by some trace logging) only runs after the FooWithOutAndRefParameters call completes...automagically (even though that code resides in the same method). It looks a little confusing to me. (I have always used callbacks for this kind of thing.)

EndInvoke will block the execution until the thread (method) initiated by the BeginInvoke finishes. In this context, it's analogous to a thread join.

Using this method do I HAVE to call EndInvoke. Can I just invoke the method asyncronously and forget it happened? Any downsides to this?

You must always call EndInvoke (see below). There are probably many reasons for that, but the one that I think it's the most important is that if the method failed, by throwing an exception, you won't get the exception until EndInvoke is called.

If I don't call EndInvoke (as is shown in this method) should I then always have a callback? Even if the callback does nothing.

The callback must call EndInvoke in that case, from the callback. So only the callback is optional.

If the answers YOU SHOULD... then do you call EndInvoke OR define a callback? (The advantage to defining a callback being that you are notified of the result)

You do not have to define the callback, but if you do, you call EndInvoke in it.

It's up to you to understand which scenario is better: be notified, completely asynchronously, that the method finished or force a join with the method (thus blocking the calling thread). It's all about control, and you should do one or another, or even both.

BTW I know I could check for errors or log resuls in the EndInvoke or callback (and I might in fact do that). What I was wondering is ARE THERE RISKS from not calling EndInvoke or defining a callback (memory leaks for example)? What is the best practice.

Not inherently, no, I don't believe that there are risks. But you must always check if the method failed or completed successfully.


From MSDN, here are the options of what can be done after a BeginInvoke:

  • Do some work and then call EndInvoke to block until the call completes.

  • Obtain a WaitHandle using the IAsyncResult.AsyncWaitHandle property, use its WaitOne method to block execution until the WaitHandle is signaled, and then call EndInvoke.

  • Poll the IAsyncResult returned by BeginInvoke to determine when the asynchronous call has completed, and then call EndInvoke.

  • Pass a delegate for a callback method to BeginInvoke. The method is executed on a ThreadPool thread when the asynchronous call completes. The callback method calls EndInvoke.


OBS: As @ScottChamberlain said in the comments, MSDN states that:

You can call EndInvoke to retrieve the return value from the delegate, if neccesary, but this is not required. EndInvoke will block until the return value can be retrieved.

I think the reason behind it that, when dealing with Controls, you are operation on the UI Thread. Since EndInvoke blocks the thread, there might be reasons for you to not want to do that. Still, I'd recommend using a callback or polling for completion in order to make sure you method has completed successfully. This would make your program more robust (or error-resilient).

Solution 3

As a matter of practice, you should call EndInvoke because the caller may have handlers subscribed to the events that may not matter to your processing, but may matter to the consumer so as to ensure certain kinds of processing can take place at a known time/application state.

Share:
10,422
Seth Spearman
Author by

Seth Spearman

Self-taught. Geek.

Updated on July 29, 2022

Comments

  • Seth Spearman
    Seth Spearman almost 2 years

    I found the following code snippet on CodeProject on calling methods asynchronously at ... http://www.codeproject.com/Articles/14931/Asynchronous-Method-Invocation

    private void CallFooWithOutAndRefParameters()
    {
        // create the paramets to pass to the function
        string strParam1 = "Param1";
        int intValue = 100;
        ArrayList list = new ArrayList();
        list.Add("Item1");
    
        // create the delegate
        DelegateWithOutAndRefParameters delFoo =
          new DelegateWithOutAndRefParameters(FooWithOutAndRefParameters);
    
        // call the beginInvoke function!
        IAsyncResult tag =
            delFoo.BeginInvoke(strParam1,
                out intValue,
                ref list,
                null, null);
    
        // normally control is returned right away,
        // so you can do other work here...
    
        // calling end invoke notice that intValue and list are passed
        // as arguments because they might be updated within the function.
        string strResult =
            delFoo.EndInvoke(out intValue, ref list, tag);
    
        // write down the parameters:
        Trace.WriteLine("param1: " + strParam1);
        Trace.WriteLine("param2: " + intValue);
        Trace.WriteLine("ArrayList count: " + list.Count);
        Trace.WriteLine("return value: " + strResult);
    }
    

    There are a couple of things I don't understand about this code.

    Per the comment control is returned immediately to the calling code when it hits the BeginInvoke line.

    Does that mean that the code that follows (EndInvoke followed by some trace logging) only runs after the FooWithOutAndRefParameters call completes...automagically (even though that code resides in the same method). It looks a little confusing to me. (I have always used callbacks for this kind of thing.)

    Using this method do I HAVE to call EndInvoke. Can I just invoke the method asyncronously and forget it happened? Any downsides to this?

    If I don't call EndInvoke (as is shown in this method) should I then always have a callback? Even if the callback does nothing.

    If the answers YOU SHOULD...then do you call EndInvoke OR define a callback? (The advantage to defining a callback being that you are notified of the result)

    BTW I know I could check for errors or log resuls in the EndInvoke or callback (and I might in fact do that). What I was wondering is ARE THERE RISKS from not calling EndInvoke or defining a callback (memory leaks for example)? What is the best practice.

    Seth