Why is my BeginInvoke method not async?
Asked Answered
G

7

8

In order to avoid freezing of GUI, I wanted to run method connecting to DB asynchronously. Therefore I have written this:

DelegatLoginu dl = ConnectDB;

IAsyncResult ar = dl.BeginInvoke(null, null);

var result = (bool)dl.EndInvoke(ar);

But it is still freezing and I do not understand why. I thought BeginInvoke ensures the invoked code runs in another thread. Thank you!

Gloria answered 5/5, 2010 at 9:24 Comment(0)
P
13

Calling EndInvoke() will block until the BeginInvoke() call has completed.

You need this kind of pattern in order for your long-running method to invoke a callback when it finishes:

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

    // Create the callback delegate.
    AsyncCallback cb = new AsyncCallback(MyAsyncCallback);

    // Initiate the Asynchronous call passing in the callback delegate
    // and the delegate object used to initiate the call.
    IAsyncResult ar = dlgt.BeginInvoke(3000, out iExecThread, cb, dlgt); 
}

public void MyAsyncCallback(IAsyncResult ar)
{
    string s ;
    int iExecThread ;

    // Because you passed your original delegate in the asyncState parameter
    // of the Begin call, you can get it back here to complete the call.
    MethodDelegate dlgt = (MethodDelegate) ar.AsyncState;

    // Complete the 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() ) );
}
Phaeton answered 5/5, 2010 at 9:26 Comment(3)
Do I need to use AsyncCallBack class or I can pass simple delegate?Gloria
It has to be an AsyncCallBack delegate, i.e. your function must look like the MyAsyncCallback() example above - return void, and take in IAsyncResult as a parameter.Phaeton
I have tested this code locally and it doesn't work (it compiles, but it does not show anything on screen): ideone.com/V8b2NYSouthwards
P
5

See the description of EndInvoke here, specifically:

The EndInvoke() function is used to retrieve the results of the asynchronous call. It can be called anytime after BeginInvoke(). If the asynchronous call has not completed yet, EndInvoke() blocks until it completes.

Piperonal answered 5/5, 2010 at 9:27 Comment(0)
B
2

You're immediately blocking your UI thread when calling dl.EndInvoke(ar). This kind of defeats the whole purpose of having an async call.

Baynebridge answered 5/5, 2010 at 9:26 Comment(2)
Well, it was mz guess..so what is this good for? I thought it does all the connection stuff in backround and then only returns :(Gloria
The BeginXxx returns just after the call, at which point the connection stuff is being handled in the background. When the result is ready, you'll get notified (either by a callback or by polling on the WaitHandle in the IAsyncResult returned by the BeginXxx call). At this point you invoke the EndXxx to retrieve the result (or get exceptions which happended in the call). Calling EndXxx early forces a wait until the result is ready.Abrahamsen
F
1

There's 4 different patterns to using the async model in .NET as this question covers very well.

You're using the "I'll call you" approach. However if you want to wait until the work item has finished, the best technique is to use a Mutex (the WaitHandle):

void Run()
{
    Action<string> doWork = DoWork;
    IAsyncResult result = doWork.BeginInvoke("I will call you", null, null);

    // You "call the method" - wait 10 seconds for the method to finish.
    bool success = result.AsyncWaitHandle.WaitOne(10 * 1000);
}

void DoWork()
{
}

I suspect you don't want to block, in which case "fire and forget" causes the least headaches.

Foote answered 12/5, 2010 at 9:26 Comment(0)
D
0

Specify a method to be called when the call is completed in BeginInvoke (like dl.BeginInvoke(null, OnConnectCompleted)). Then the thread will not be blocked.

Disinherit answered 5/5, 2010 at 9:28 Comment(0)
T
0

Why not just use a BackgroundWorker instead?

Trouveur answered 5/5, 2010 at 9:48 Comment(0)
S
0

Call to EndInvoke will block your current thread. You should pass a delegate into the BeginInvoke instead of calling the EndInvoke

Sedentary answered 5/5, 2010 at 10:57 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.