Threading - Callback events, delegates

MaxinA

Member
Joined
May 11, 2007
Messages
15
Location
Canada
Programming Experience
10+
I am working on a multithreaded app that is not working exactly as it needs to.

I am using delegate subs in order to do async callbacks from a collection of classes. This works fine except for one small detail. When the event is raised within the callback class, it propogates to the parent application, and is still executing on the child thread, not the application's main thread. The problem with this is that I need the main thread to do the actual work.

Is there a way to "hand off" the callback to the main thread like I expected it too?

Thanks in advance..

Andrew
 
Just to clear this, I wouldn't expect an asynchronous callback to change thread context, if it operates in a different thread there is no reason it should suddenly change.

If you need to invoke a method on the UI thread pass a reference of the form (Me) to it so it can do that.

You can also use the same mechanism the BackgroundWorker uses, the AsyncOperation/-Manager.

If you define the delegate for the event you can also get the invocation list from it and check each subscribed delegates target, which enables you to do the same as the first option, check if invoke is required and possibly invoke the method on the targets thread.
 
John,

Well, The nature of the problem is that the worker threads are performing difference scanning, and merely popping up notifications of changes in a list.. The main calling thread is the one that actually has to do anything with the returned result from the worker threads.

Do you have an example of the methods you mentioned in your post?

Thanks

Andrew
 
Ok, I've created two basic bare-bone classes that implements the two first options, check them out:
VB.NET:
Public Class asyncInvoking
    Public Event Finished As EventHandler
    Private Delegate Sub evt(ByVal e As EventArgs)
    Private d As New evt(AddressOf onFinish)
    Private cbContext As Control

    Public Sub New(ByVal callbackcontext As Control)
        Me.cbContext = callbackcontext
    End Sub

    Public Sub workAsync()
        Dim m As New MethodInvoker(AddressOf worker)
        m.BeginInvoke(AddressOf callback, Nothing)
    End Sub

    Public Sub work()
        worker()
        Me.onFinish(New EventArgs)
    End Sub

    Private Sub worker()
        Threading.Thread.Sleep(2000)
    End Sub

    Private Sub callback(ByVal ia As IAsyncResult)
        cbContext.Invoke(d, New EventArgs)
    End Sub

    Protected Sub onFinish(ByVal e As EventArgs)
        RaiseEvent Finished(Me, e)
    End Sub
End Class
VB.NET:
Public Class asyncOping
    Public Event Finished As EventHandler
    Private asyncOp As System.ComponentModel.AsyncOperation
    Private asyncOpCompleted As New Threading.SendOrPostCallback(AddressOf OpComplete)

    Public Sub workAsync()
        Me.asyncOp = System.ComponentModel.AsyncOperationManager.CreateOperation(Nothing)
        Dim m As New MethodInvoker(AddressOf worker)
        m.BeginInvoke(AddressOf callback, Nothing)
    End Sub

    Public Sub work()
        worker()
        Me.onFinish(New EventArgs)
    End Sub

    Private Sub worker()
        Threading.Thread.Sleep(2000)
    End Sub

    Private Sub callback(ByVal ia As IAsyncResult)
        asyncOp.PostOperationCompleted(asyncOpCompleted, New EventArgs)
    End Sub

    Private Sub OpComplete(ByVal state As Object)
        onFinish(state)
    End Sub

    Protected Sub onFinish(ByVal e As EventArgs)
        RaiseEvent Finished(Me, e)
    End Sub
End Class
test code:
VB.NET:
Private WithEvents x As New asyncInvoking(Me) 'or New asyncOping

Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    x.workAsync()
End Sub

Private Sub x_finished(ByVal sender As Object, ByVal e As EventArgs) Handles x.finished
    Me.Text = "hello safe async"
End Sub
This and related links is perhaps interesting: Asynchronous Programming Design Patterns.
 
Back
Top