B
Brad Brening
I am building a class that has a function that I would like to run
asycronously. When the function is complete I would like to notify the
calling thread by raising an event or using a delegate. The handler for the
event (or the delegate callback) should run in the parent thread - not on
the asyncronous thread created while the function ran.
So, basically, I want my parent (form, class, control) to call my class
function - which spawns a thread and does some work. Once this work is done
I want to notify the parent and allow it to process the result in the parent
thread. Simple? Maybe. I can't make it happen.
I tried messing around with the AsyncCallback and IAsyncResult methods using
delegates. This is all fine and good, however the callback runs in the
spawned thread and not the parent thread.
I found some dirty hacks that referenced the parent form when the class is
instantiated and using the forms "BeginInvoke" method to perform the
operation. That would be good if I could count on my class always being
instantiated by a form - but this class could be called from another class
or even a user control. That rules out that avenue.
So, my question is this. What is the best way to achieve asyncronous
execution with the ability to notify the main thread when the operation is
complete? Further, this ability needs to be totally invisible to the client.
Am I missing something with using a Delegate function and the ".BeginInvoke"
and ".EndInvoke" methods that is keeping me from being notified on the main
thread?
Here is my code for the class:
visual basic code:
Imports System
Imports System.Runtime.Remoting.Messaging
Public Delegate Function QueryCallback() As Boolean
Public Class cQuery
Public Test As Integer
Public Function Query() As Boolean
Dim I As Integer
' just tie up this thread for a little while.
For I = 1 To 1000000
Test = I
Next
Query = True
End Function
Public Function BeginQuery(ByVal aCallBack As AsyncCallback, ByVal
AsyncState As Object) As IAsyncResult
Dim cbQuery = New QueryCallback(AddressOf Query)
BeginQuery = cbQuery.BeginInvoke(aCallBack, AsyncState)
End Function
Public Function EndQuery(ByVal iaResult As IAsyncResult) As Boolean
Dim cbQuery As QueryCallback
Dim result As AsyncResult
result = CType(iaResult, AsyncResult)
cbQuery = result.AsyncDelegate
EndQuery = cbQuery.EndInvoke(iaResult)
End Function
End Class
Here is the code for my Form (to test):
visual basic code:
' snip - basic form with a button
Private tc As New cQuery()
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim ac As New AsyncCallback(AddressOf MyCallback)
If Thread.CurrentThread.Name Is Nothing Then
Thread.CurrentThread.Name = "MAIN THREAD"
Dim Result As IAsyncResult = tc.BeginQuery(ac, tc)
MessageBox.Show("Current Thread Name = " &
Thread.CurrentThread.Name)
Console.WriteLine("LEAVING BUTTON1_CLICK HANDLER!")
End Sub
Private Sub MyCallback(ByVal result As IAsyncResult)
Console.WriteLine("ENTERING CALLBACK")
tc.EndQuery(result)
MessageBox.Show("Current Thread Name = " &
Thread.CurrentThread.Name)
End Sub
asycronously. When the function is complete I would like to notify the
calling thread by raising an event or using a delegate. The handler for the
event (or the delegate callback) should run in the parent thread - not on
the asyncronous thread created while the function ran.
So, basically, I want my parent (form, class, control) to call my class
function - which spawns a thread and does some work. Once this work is done
I want to notify the parent and allow it to process the result in the parent
thread. Simple? Maybe. I can't make it happen.
I tried messing around with the AsyncCallback and IAsyncResult methods using
delegates. This is all fine and good, however the callback runs in the
spawned thread and not the parent thread.
I found some dirty hacks that referenced the parent form when the class is
instantiated and using the forms "BeginInvoke" method to perform the
operation. That would be good if I could count on my class always being
instantiated by a form - but this class could be called from another class
or even a user control. That rules out that avenue.
So, my question is this. What is the best way to achieve asyncronous
execution with the ability to notify the main thread when the operation is
complete? Further, this ability needs to be totally invisible to the client.
Am I missing something with using a Delegate function and the ".BeginInvoke"
and ".EndInvoke" methods that is keeping me from being notified on the main
thread?
Here is my code for the class:
visual basic code:
Imports System
Imports System.Runtime.Remoting.Messaging
Public Delegate Function QueryCallback() As Boolean
Public Class cQuery
Public Test As Integer
Public Function Query() As Boolean
Dim I As Integer
' just tie up this thread for a little while.
For I = 1 To 1000000
Test = I
Next
Query = True
End Function
Public Function BeginQuery(ByVal aCallBack As AsyncCallback, ByVal
AsyncState As Object) As IAsyncResult
Dim cbQuery = New QueryCallback(AddressOf Query)
BeginQuery = cbQuery.BeginInvoke(aCallBack, AsyncState)
End Function
Public Function EndQuery(ByVal iaResult As IAsyncResult) As Boolean
Dim cbQuery As QueryCallback
Dim result As AsyncResult
result = CType(iaResult, AsyncResult)
cbQuery = result.AsyncDelegate
EndQuery = cbQuery.EndInvoke(iaResult)
End Function
End Class
Here is the code for my Form (to test):
visual basic code:
' snip - basic form with a button
Private tc As New cQuery()
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles Button1.Click
Dim ac As New AsyncCallback(AddressOf MyCallback)
If Thread.CurrentThread.Name Is Nothing Then
Thread.CurrentThread.Name = "MAIN THREAD"
Dim Result As IAsyncResult = tc.BeginQuery(ac, tc)
MessageBox.Show("Current Thread Name = " &
Thread.CurrentThread.Name)
Console.WriteLine("LEAVING BUTTON1_CLICK HANDLER!")
End Sub
Private Sub MyCallback(ByVal result As IAsyncResult)
Console.WriteLine("ENTERING CALLBACK")
tc.EndQuery(result)
MessageBox.Show("Current Thread Name = " &
Thread.CurrentThread.Name)
End Sub