Threading Questions

vinnie881

Well-known member
Joined
Sep 3, 2006
Messages
152
Programming Experience
3-5
I am a new to threading. I have built my application and it works well, but here are some issues I am hopping someone can help me with.

1. How to stop a thread saftly (I don't want to stop it if it's in the middle of running something vital)

2. Catch a event (Like when my thread has finished running)

3. Handle Exceptions

Any help would be greatly appricaited.


Thanks

Also, I was looking for a threading category on this forum, but I couldn't find it. I appologize if I posted this in the wront category.
 
Using a background worker is the easiest way to do this. The background worker has hooks for process-canceled, process-ended, and process-update (i.e. for a progress bar). The background worker takes a little getting used to, but I can send you sample code to show you how it works if you like.

Thanks,
Chris
 
If you can send me some sample code, that would be great. Can you please illustrate how to implement the hooks.

Thanks
 
Using a background worker is the easiest way to do this. The background worker has hooks for process-canceled, process-ended, and process-update (i.e. for a progress bar). The background worker takes a little getting used to, but I can send you sample code to show you how it works if you like.

Thanks,
Chris

His profile says he's using VS 2003, the Background worker is only for VS 2005 and higher

He can't use that as an option.


Here's an article on threading: http://www.codeproject.com/vb/net/threadingvbnet.asp
 
I have purchased vs.2005 but yet to install it (I'm a little lazy :)). I read the article you posted, and Its good, but I think I'm past that point. I really need to find a way to know when a threads done (Without a constant loop. I think I might pass a delegate then invoke the related sub when it finishes processing, but I'm not sure if this is the best way.).


Please show me the code in 05. Also if someone can tell me how to do it in 03 I'd appriciate that as well.
 
I have purchased vs.2005 but yet to install it (I'm a little lazy :)). I read the article you posted, and Its good, but I think I'm past that point. I really need to find a way to know when a threads done (Without a constant loop. I think I might pass a delegate then invoke the related sub when it finishes processing, but I'm not sure if this is the best way.).


Please show me the code in 05. Also if someone can tell me how to do it in 03 I'd appriciate that as well.

Here is a sample application in VB 2005. This is all code for the form called main. The form only has one object - a progressbar called ProgressBar. I have only added a few notes to the codes, so I hope you can follow. If you have any questions, please let me know. After the code for the Class Main, you will see a class Background work. This is where the work is actually done.

VB.NET:
Public Class Main

    Dim Worker As BackgroundWork = New BackgroundWork

    Private Sub Main_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Loa
        Worker.Call_on_End = New BackgroundWork.Ended(AddressOf Ended)
        Worker.Report_Prog = New BackgroundWork.Advance_Progress(AddressOf Set_Progress)
        Worker.Start()
    End Sub

    Public Sub Set_Progress(ByVal index As Integer, ByVal max As Integer, ByVal Title As String)
        ProgressBar.Maximum = max
        ProgressBar.Value = index
        If Title.ToString <> "" Then Me.Text = Title
        'Here is where you put what is to be done on progress update.
    End Sub

    Public Sub Ended()
        'Here is where you put what is to be done on process end.
    End Sub

End Class

Public Class BackgroundWork

    Public Sub Work(Optional ByVal Worker As System.ComponentModel.BackgroundWorker = Nothing, Optional ByVal e As System.ComponentModel.DoWorkEventArgs = Nothing, Optional ByVal oProgress As Object = Nothing)
        For I As Integer = 1 To 100
            'Here is where you put the work to be done.
            System.Threading.Thread.Sleep(10)
            Worker.ReportProgress(0, New Status(I, 100, ""))
        Next
    End Sub

    Private WithEvents Worker As New System.ComponentModel.BackgroundWorker
    Public Delegate Sub Advance_Progress(ByVal index As Integer, ByVal max As Integer, ByVal title As String)
    Public Report_Prog As Advance_Progress
    Public Delegate Sub Ended()
    Public Call_on_End As Ended
    Private Cancelled As Boolean = False

    Sub Start()
        Report_Prog(0, 0, "")
        Worker.WorkerReportsProgress = True
        Worker.WorkerSupportsCancellation = True
        Worker.RunWorkerAsync()
    End Sub

    Private Sub Background_ProgressChanged(ByVal sender As Object, ByVal e As System.ComponentModel.ProgressChangedEventArgs) Handles Worker.ProgressChanged
        Dim Progress As Status = CType(e.UserState, Status)
        Report_Prog(Progress.Index, Progress.Max, Progress.Title)
    End Sub

    Private Sub Background_DoWork(ByVal sender As Object, ByVal e As System.ComponentModel.DoWorkEventArgs) Handles Worker.DoWork
        Dim Worker As System.ComponentModel.BackgroundWorker = CType(sender, System.ComponentModel.BackgroundWorker)
        Work(Worker, e)
    End Sub

    Public Sub Cancel()
        Worker.CancelAsync()
        Cancelled = True
        Call_on_End()
    End Sub

    Private Class Status

        Private _index As Integer = 0
        Private _max As Integer = 0
        Private _title As String = DBNull.Value.ToString

        ReadOnly Property Index() As Integer
            Get
                Return _index
            End Get
        End Property

        ReadOnly Property Max() As Integer
            Get
                Return _max
            End Get
        End Property

        ReadOnly Property Title() As String
            Get
                Return _title
            End Get
        End Property

        Sub New(ByVal Index As Integer, ByVal Max As Integer, Optional ByVal Title As String = "")
            _index = Index
            _max = Max
            _title = Title
        End Sub

    End Class

End Class
 
Alright, let me ask the dumb question...

I can do the exact same thing using the "Thread" object in 03, so what's the differance between a background worker, and a thread where I set it to run as background? Is there any?


Thanks for the help, that's what I thought I needed to do, just pass the delegate the objet.

This answers question 2.

Now I am confused still with 1 and 3.

I see you have a cancel sub in the code, but how do you invoke it from the calling class to cancel that active thread? Plus is this the best way to "SAFELY" stop a thread? Here the predicament. I have code that can not just be aborted (I have designated stopping points in there like below)

If cancelled = true
thread.abort
end if

now the issue is if I cancel by clicking a button in my calling class, what's the best way to indicate this to the running thread?


Finally Error trapping. How do I catch errors in a thread properly?

Thanks very much for everyones help thus far.
 
Well, I must admit that I am not a seasoned programmer, and I am fairly new to background workers. I began using them a few months ago. I had tried to use threading, but at least in VB.net 2005, if you try use a delegate while multi-threading, it throws an error. The background worker is supposed to be the safest way to handle this. As I understand it, is the user cancels and you pass that to the worker, the worker could set a cancelled boolean variable to true and stop at the next stop point. As far as exceptions, I only handle exceptions using TryCatchFinally statements. I don't know if you have used this or if you used more advanced methods, but it has worked wonderfully for me.

I hope I have answered most of your questions, and I would be happy to help in any other way I can.

Thanks,
Chris
 
I can do the exact same thing using the "Thread" object in 03, so what's the differance between a background worker,
Convenience. It is convenient to set up, adding it as a component or manual WithEvents allows the handler method inserted in code for you, everything about progress reporting and the cancelling mechanism is already coded and readily available. The progress and completion events are already thread-safe without you needing to make thread adjustments for all methods that access UI elements. In all it gives you ready standard code and saves time.

About thread cancel/abort, the safe and recommended way to stop a thread is to set a Boolean flag or similar notification that the working method checks periodically and stops its work cleanly if asked to, Thread.Abort is not clean unless you know the worker code well enough to say for sure there is nothing there at any time that will leave a mess if its promptly abrupted. BGW already includes this way of notifying the worker by calling CancelAsync to make the request, and checking the PendingCancellation property to allow worker to stop.

Error trapping? You catch those exceptions you can handle with TryCatch blocks, uncaught exceptions will in the BGW case be reported through the RunWorkerCompleted event and you can read it there in the events e.Error property. So the BGW does in fact internally TryCatch the whole DoWork delegate call and just pass this info on to its completion event.
 
Thanks very much, this really clarifies things. If someone can please post a bit of sample code to pass the cancelled boolean to a runnin thread, I'd very much appriciate it.

Thanks
 
VB.NET:
Private Sub btnStart_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStart.Click
    Dim t As New Threading.Thread(AddressOf EndlessWork)
    t.Start()
End Sub

Private Sub btnStop_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnStop.Click
    Me.cancel = True
End Sub

Private cancel As Boolean

Sub EndlessWork()
    Me.cancel = False
    Do Until cancel
        Threading.Thread.Sleep(500) 'does something
    Loop
End Sub
 
btnStop is in calling class, EndlessWork method runs on other thread. I don't understand your question.
 
Yes,

My thread runs a differant class

VB.NET:
Dim c As New myclass("MYVARIABLES")
dim t as threading.Thread(AddressOf myclass.EndlessWork)
t.Start()

Now I need to send my cancel variable to t
 
"MyClass" is a reserved keyword, so you can't use that for class name, my examples use name "yourclass" instead.
Your thread doesn't run a different class, it runs a method of a class instance. It is the class instance you set the cancel flag for, the method will check its class member to see if someone interacting with it has requested it to stop. So use a public/friend method or property, or simply a field if you're lazy, here are the options:
VB.NET:
Class yourclass1
    Friend Cancel1 As Boolean
End Class
VB.NET:
Class yourclass2
    Private _cancel As Boolean
    Friend Property Cancel2() As Boolean
        Get
            Return Me._cancel
        End Get
        Set(ByVal value As Boolean)
            Me._cancel = value
        End Set
    End Property
End Class
VB.NET:
Class yourclass3
    Private _cancel As Boolean
    Friend Sub Cancel3()
        Me._cancel = True
    End Sub
End Class
Usage goes as follows from your example instance "c":
c.Cancel1 = True
c.Cancel2 = True
c.Cancel3()

The method option would be preferred in this case.
 
Back
Top