FatalError
FatalError

Reputation: 77

Begin end asynchronuos method call

Here is a code snippet from Microsoft. I have a doubt in asynchronous method calling.

since we are calling end.Invoke after Begin-invoke it is looks like we are doing a synchronous call. because we are waiting for the returned value of asynchronous call.

what happens if the asynchronous method didn't completes while we are calling end.invoke. can we just proceed to next statement or we have to wait.

if this is happening in multithreaded environment how they are handling callback signal to correct thread.

public void DemoEndInvoke()
{
    MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
    string s ;
    int iExecThread;

    // Initiate the asynchronous call.
    IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, null, null);  

    // Do some useful work here. This would be work you want to have
    // run at the same time as the asynchronous call.

    // Retrieve the results of the asynchronous call.
    s = dlgt.EndInvoke (out iExecThread, ar) ;  

    MessageBox.Show (string.Format ("The delegate call returned the string:   \"{0}\", 
                               and the number {1}", s, iExecThread.ToString() ) );
}

Upvotes: 1

Views: 6127

Answers (2)

Andrew Vermie
Andrew Vermie

Reputation: 633

You have to wait; from Calling Synchronous Methods Asynchronously:

EndInvoke might block the calling thread because it does not return until the asynchronous call completes

The mechanism that is used to perform the blocking is likely similar to the following:

IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, null, null);

// wait for async invocation to complete
ar.AsyncWaitHandle.WaitOne()

But you must call EndInvoke (see this question for more discussion).

If you don't want to wait, then you need to use the asynchronous callback to perform the EndInvoke:

dlgt.BeginInvoke(3000, out iExecThread, ar => dlgt.EndInvoke(out iExecThread, ar), null);

When you do this, you won't know the results of your async invocation; you can't get the return value, and you won't know what changes are made to any out parameters (counter-intuitively, BeginInvoke doesn't change any of its out parameters at all).


With that said, .NET gained excellent asynchronous programming APIs starting in .NET 4; the newer patterns are better structured, more powerful, and easier to work with (especially in 4.5). If you have the option, you should look at .NET 4's TPL and .NET 4.5's TAP.

Upvotes: 0

NeddySpaghetti
NeddySpaghetti

Reputation: 13495

what happens if the asynchronous method didn't completes while we are calling end.invoke. can we just proceed to next statement or we have to wait.

Yes, EndInvoke is a blocking call. You can make the whole thing much easier to use if you use the TaskFactory.FromAsync method. That will convert your API to return a task which you can await.

Your code should look something like this (I haven't compiled it):

public async void DemoEndInvoke()
{
    MethodDelegate dlgt = new MethodDelegate (this.LongRunningMethod) ;
    string s ;
    int iExecThread;

    await Task.Factory.FromAsync(MethodDelegate.BeginInvoke, MethodDelegate.EndInvoke, iExecThread);

    MessageBox.Show (string.Format ("The delegate call returned the string:   \"{0}\", and the number {1}", s, iExecThread.ToString() ) );
}

Using await the compiler will generate a state machine which saves the current SynchronizationContext and then restores it once the task completes and it executes the rest of the method on the same SynchronizationContext. If you await on the UI thread, the code after the await will also execute on the UI thread. For console apps and unit tests that isn't the case though.

If all you are trying to do is run a long running method on a background thread, you can simply use Task.Run in .net 4.5 or TaskFactory.StartNew in .net 4.0. For the difference between the two, see this article.

public async void DemoEndInvoke()
{
    await Task.Run(() => this.LongRunningMethod());

    MessageBox.Show (string.Format ("The delegate call returned the string:   \"{0}\", and the number {1}", s, iExecThread.ToString() ) );
}

Upvotes: 5

Related Questions