New to threading.. Please help..

W

W.G. Rowland

In some ways I'm starting to miss the simpler days of VB5..

Anyway, here's my problem. I'm trying to build a MSDE client using an MDI
Parent/Child interface. Enough of the tasks the program will have to
perform are time consuming that I would like to build a progress indicator
dialogue to track progress so the user knows things are going on.

Now, to avoid display corruption from long processes tying up the thread I'm
running longer routines (like the one that transfers the old Access database
into the new SQL format and takes several minutes) I'm running these
processes in their own threads. This allows me to keep all the UI code in
one thread, and not have the display corrupt..

The problem I have is not knowing how to pass information from the worker
thread to the UI thread.. Specifically, I need the worker thread to be able
to tell the progress window when it needs to update information (up the
value of the progress bar, change the caption to tell the user what's going
on, etc.), and also to let the progress window know when the worker thread
is done, so it can terminate itself..

From my research it seems I should probably be creating events and handlers
for the progress window, which I know how to do (I think..), and then having
the worker thread raise the events (or call methods in the progress window
that raise them)..

That's the part I don't know how to do.. How do I get code in one thread to
call routines in another?

Can anyone help me out? I've been beating my head against this one all day,
and all I have to show for it is a headache..

Thanks in advance,
W.G. Rowland
 
F

Fergus Cooney

Hi W.G.,

You can communicate with the UI thread by using BeginInvoke of the Control
that you are interested in. This sends a message to it via the message queue
and is the safe way to do it. The Control then calls your Worker class back,
using a Worker class method, but still running in the UI thread. So it has
thread-safe access to your progress data.

Below is an example that I put together for a guy who wanted to have
multiple Threads each processing the download of image data from cameras. The
Threads update a ListBox to show progress.

To use it, create a Form and drop a ListBox on it (ListBox1). Put the code
below into a module (any name.vb). Add this to Form_Load and hit F5.

Sub Form_Load (...)
lstCameras = Me.ListBox1
LetsHaveSomeCameras

The Module is just the testbed. The useful part is the Class.

I hope this proves enlightening. ;-)

Regards,
Fergus

<code>
Public Module Threading_CameraThreadsAndFeedbackToGUI

Public lstCameras As ListBox

Private Dim aoCameras(5) As Camera

Public Sub LetsHaveSomeCameras
Dim I As Integer
For I = 0 To 4
aoCameras(I) = New Camera ("Camera " & I + 1)
aoCameras(I).Start ("Hi from " & I + 1)
Threading.Thread.Sleep (250) 'Stagger them for fun.
Next
End Sub

Dim CameraNum As Integer
Public Sub ThatsAWrap
If CameraNum <= 4 Then _
aoCameras (CameraNum).Stop
CameraNum += 1
End Sub

'======================================================================
Public Class Camera
Delegate Sub CameraStarter (sFoo As String)
Delegate Sub FeedbackCallBack (sText As String)

Private oThread As Thread
Private oCameraStarter _
As New CameraStarter (AddressOf GoCameraGo)
Private sName As String

'==============================================
'This will execute in the caller's thread.
Public Sub New (sThisName As String)
sName = sThisName & " "
End Sub

'==============================================
'This will execute in the caller's thread.
Public Sub Start (sFoo As String)
'This will call GoCameraGo with (sFoo)
oCameraStarter.BeginInvoke (sFoo, Nothing, Nothing)
End Sub

'==============================================
'This will execute in the caller's thread.
Public Sub [Stop]
Dim S As String = oThread.Name
oThread.Abort 'Kill the Thread immediately
oThread.Join 'Wait for it to go.
End Sub

'==============================================
'This is called by oCameraStarter.BeginInvoke().
'It will execute in its own (ThreadPool) thread.
Public Sub GoCameraGo (sFoo As String)
Dim GiveFeedback _
As New FeedbackCallBack (AddressOf AddToList)
Dim sMess As String
Try
oThread = Thread.CurrentThread
oThread.Name = sName
Dim I As Integer
Dim asArgList As Object()
For I = 1 To 8
asArgList = New Object() _
{sName & "[" & I & "]: " & sFoo}
'Tell lstCameras via Message Queue to "Come get some!!"
lstCameras.BeginInvoke (GiveFeedback, asArgList)
Threading.Thread.Sleep (750)
Next
asArgList = New Object() {sName & ": Finshed"}
lstCameras.BeginInvoke (GiveFeedback, asArgList)
Catch ex As ThreadInterruptedException
End Try
End Sub

'==============================================
'This will execute in the ListBox's thread.
Private Sub AddToList (sText As String)
lstCameras.Items.Add (sText)
lstCameras.SelectedIndex = lstCameras.Items.Count - 1
End Sub
End Class
End Module
</code>
 
T

Tom Shelton

In some ways I'm starting to miss the simpler days of VB5..

Anyway, here's my problem. I'm trying to build a MSDE client using an MDI
Parent/Child interface. Enough of the tasks the program will have to
perform are time consuming that I would like to build a progress indicator
dialogue to track progress so the user knows things are going on.

Now, to avoid display corruption from long processes tying up the thread I'm
running longer routines (like the one that transfers the old Access database
into the new SQL format and takes several minutes) I'm running these
processes in their own threads. This allows me to keep all the UI code in
one thread, and not have the display corrupt..

The problem I have is not knowing how to pass information from the worker
thread to the UI thread.. Specifically, I need the worker thread to be able
to tell the progress window when it needs to update information (up the
value of the progress bar, change the caption to tell the user what's going
on, etc.), and also to let the progress window know when the worker thread
is done, so it can terminate itself..

From my research it seems I should probably be creating events and handlers
for the progress window, which I know how to do (I think..), and then having
the worker thread raise the events (or call methods in the progress window
that raise them)..

That's the part I don't know how to do.. How do I get code in one thread to
call routines in another?

Can anyone help me out? I've been beating my head against this one all day,
and all I have to show for it is a headache..

Thanks in advance,
W.G. Rowland

Fergus gave a pretty good example... But I thought I'd throw out a link
that could probably really help. Don't be scared off because the code
is in C#, but it is a 3 part article that basically does exactly what
your asking - spins off workers, that signal their progress back to the
UI :)

Here is the link to the first article... (you should see the other two
over in the side bar):

http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnforms/html/winforms06112002.asp

HTH
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top