views:

143

answers:

2

My question involves async operations in VB .NET.

Given the following:

Delegate WorkerDelegate(Byval asyncOp As AsyncOperation)

Public Sub StartWork()        
    Dim worker as new WorkerDelegate(AddressOf DoWork)
    Dim asyncOp as AsyncOperation = AsyncOperationManager.CreateOperation(New Object)

    // begin work on different thread
    worker.BeginInvoke(asyncOp, Nothing, Nothing)
End Sub

Private Sub DoWork(Byval asyncOp as AsyncOperation)
    // do stuff

    // work finished, post
    asyncOp.PostOperationCompleted(AddressOf OnDownloadFinished, Nothing)                
End Sub

Private Sub OnDownloadFinished()
    // Back on the main thread now

End Sub

Most resources I've read say that if you use BeginInvoke on a delegate you must call EndInvoke. In my example above I am using the PostOperationCompleted method to switch threads back and report the operation has finished.

Do I still need to get an IAsyncResult when I call worker.BeginInvoke and add worker.EndInvoke in the OnDownloadFinished method?

+1  A: 

It's best practice to call EndInvoke, because that's when resources assigned by the AsyncResult are cleaned.

However, AFAIK the async result used by the asynchronous delegate does not use any resource if you don't access the WaitHandle property, so not calling the EndInvoke may have no impact.

In your scenario, you should consider using ThreadPool.QueueUserWorkItem.

SelflessCoder
+1 for QueueUserWorkItem. Use that when you can, raw invokes and threads when you must.
Greg D
Agree with QueueUserWorkItem, but the bit about EndInvoke cleaning up resources is nonsense. You can call EndInvoke to retrieve the return value from the delegate, if neccesary, but this is not required.
Andomar
EndInvoke will dispose the IAsyncResult.WaitHandle if it has been accessed. Accessing WaitHandle and not calling EndInvoke will put pressure on the finalize queue in the garbage collector.
SelflessCoder
Would you still use the QueueUserWorkItem if the "work" being done was downloading a file which may take awhile to finish? The general rule for thread pool threads was they need to finish quickly, correct?
DB
Delegate.BeginInvoke queue the delegate on the ThreadPool too. Maybe you should create a new Thread instead
SelflessCoder
Good point - overlooked the delegate using the threadpool as well.
DB
For the info, Jon Skeet said you should call EndInvoke, I would not contradict him :)http://stackoverflow.com/questions/1642940/endinvoke-optional-or-not
SelflessCoder
Jon Skeet said you should call EndInvoke for a delegate. But for AsyncOperationManager, suggesting a call to EndInvoke is a pretty strange suggestion, since it will throw a TargetInvocationException.
Andomar
I added implementation to call EndInvoke and did not receive a TargetInvocationException.
DB
At which point did you add the EndInvoke call?
Andomar
In the OnDownloadFinished method.
DB
Right, my test used the wrong AsyncResult. Looks like AsyncOperationManager does not call EndInvoke, so calling it manually is actually a good suggestion. (Mental note: stop answering questions on friday night :))
Andomar
Yep, I am going to call the EndInvoke. The link above had a good comment that even if it doesn't leak now it might in a future version.Thanks for contributing, Andomar :-)
DB
A: 

In the example on MSDN, the equivalent of your OnDownloadFinished method looks like this:

// This method is invoked via the AsyncOperation object,
// so it is guaranteed to be executed on the correct thread.
private void CalculateCompleted(object operationState)
{
    CalculatePrimeCompletedEventArgs e =
        operationState as CalculatePrimeCompletedEventArgs;

    OnCalculatePrimeCompleted(e);
}

It does not call EndInvoke(). So it's safe to assume that not calling EndInvoke() in the PostOperationCompleted handler is alright.

Andomar
I agree with your logic here (yes, that link is where I got the pattern from). However, tons of the MSDN examples have errors that users point out, didn't know if not calling EndInvoke was a MS oversight
DB