Exiting a Thread and Restarting a Program on Error, VB.NET

I understand threads about as well as I understand women...  so...  I have a program I wrote, with the help of some experts that uses threads to run multiple calls to a database.

This program runs 24x7 and downloads orders from a website and enters them in quickbooks.  after the order is downloaded, it updates the website with correct stock values for every item in the store.  If the program stops in the middle of the night, we don't know about it until we come in next.  Everytime it stops, it only requires a restart to make the thing work, so... I'd like to restart the program automatically everytime it stops.

I want to use Try / Catch to restart the application.  But i'm not sure how to exit all the currently running thread to do that. After I exit all threads, I need to run this: btnEngageCode()

I'm not sure if I'm supplying enough information about the problem, please let me know if it doesn't make sense.

Thanks!

LVL 1
slightlyoffAsked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Alfred A.Commented:
Why don't you use a "Finally" in your Try/Catch.  A Finally block is always executed when execution leaves any part of the Try statement.

Try
   ....
Catch(ex As Exception)
   ....
Finally
   'Run/call your btnEngageCode here.
End Try


I hope this helps.
0
käµfm³d 👽Commented:
I imagine you'd need to track all the threads you create in some container (e.g. List<Thread>) and inside the catch block, abort all threads. To restart the function, you're going to need a loop. You also need to add some logic to exit the loop since the catch will force another loop iteration. The following is in a module, but is designed to demonstrate this idea.

I used Join() to cause the application to wait for all threads to be aborted as Calling Abort() does not always immediately kill the thread.
Imports System.Threading

Module Module1
    Private threadList As New List(Of Thread)
    Private loopAgain As Boolean = True

    Sub Main()
        While loopAgain
            Try
                btnEngageCode()
            Catch ex As Exception
                For Each th As Thread In threadList
                    th.Abort()
                Next

                For Each th As Thread In threadList
                    th.Join()
                Next
            End Try
        End While
    End Sub

    Sub btnEngageCode()
        threadList.Add(New Thread(AddressOf Test1))
        threadList.Add(New Thread(AddressOf Test2))
        threadList.Add(New Thread(AddressOf Test3))
        threadList.Add(New Thread(AddressOf Test4))

        threadList(0).Start()
        threadList(1).Start()
        threadList(2).Start()
        threadList(3).Start()

        Thread.Sleep(10000)
        Throw New AccessViolationException("Some Excecption by your app")
    End Sub

    Sub Test1()
        While True
            System.Diagnostics.Debug.Print("Test1")
        End While
    End Sub

    Sub Test2()
        While True
            System.Diagnostics.Debug.Print("Test2")
        End While
    End Sub

    Sub Test3()
        While True
            System.Diagnostics.Debug.Print("Test3")
        End While
    End Sub

    Sub Test4()
        While True
            System.Diagnostics.Debug.Print("Test4")
        End While
    End Sub
End Module

Open in new window

0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
käµfm³d 👽Commented:
P.S.

As written above, you could set "loopAgain" to False elsewhere when you needed to exit the application. You would most likely need to abort the threads there also, so you may want to write a separate function that does the looping through the list to abort.
0
Build an E-Commerce Site with Angular 5

Learn how to build an E-Commerce site with Angular 5, a JavaScript framework used by developers to build web, desktop, and mobile applications.

slightlyoffAuthor Commented:
Thanks for your response.  I understand what you did in the context of the example - but I don't quite follow how to apply it to what I'm doing - because of the multiple threads...  I've attached some of my code to explain.

The error I get - sometimes the connection the the sql server can't be made (due to an internet interuption or something stupid like that).  If I encount this error on any of the threads, btnEngageCode must run, so that any orders that have processed completely get deleted from the temp table -
otherwise, they'll be downloaded twice.

So I'm not sure where to put the:
       While loopAgain
            Try
                btnEngageCode()
            Catch ex As Exception
                For Each th As Thread In threadList
                    th.Abort()
                Next
 
                For Each th As Thread In threadList
                    th.Join()
                Next
            End Try
        End While

Thanks again for your time.  I feel like if I can just get a handle on threads and how to use them, It will open up some new ways to program that I just don't consider right now.


'The user clicks btnEngage to start the process
Private Sub btnEngage_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEngage.Click
        btnEngageCode()
End Sub

'The next sub, clears a temp table where orders are stored and sorted from multiple databases, while they wait to be processed.
Public Sub btnEngageCode()
        'Disable engage... don't want restart now that it's running.
        btnEngage.Enabled = False
        writeLog("Program Started:" & Now(), 0, "Program Start", 1)

        'Clear Temp Table in case of restart.
        Dim tempConn As New SqlConnection
        tempConn.ConnectionString = TempConnectionString
        Dim dSQL As String
        Dim dCmd As SqlCommand
        tempConn.Open()
        dSQL = "Delete FROM tempTable"
        dCmd = New SqlCommand(dSQL, tempConn)
        dCmd.ExecuteNonQuery()
        tempConn.Close()
        tempConn = Nothing

        'Begin Program
        StartItAll()
    End Sub

'Starts the main work
   Private Sub StartItAll()
        T = New Thread(AddressOf Controller)
        T.Start()
    End Sub

'Here is where all the work starts. Some of the stores are commented out because they aren't live yet. 

Private Sub Controller()
        Dim MREs As New List(Of WaitHandle)
        'Connect to Temp DB

        lblRetrieve.ForeColor = Color.White
        Dim mt As New MyThread

        'Store 1
        'mt = New MyThread
        'MREs.Add(mt.MRE)
        'mt.ConnString = Store1ConnectionString
        'mt.theOrderCount = Me.hOrderCount
        'mt.StoreID = 1
        'mt.Start()

        'Store 2
        'mt = New MyThread
        'MREs.Add(mt.MRE)
        'mt.ConnString = Store2ConnectionString
        'mt.theOrderCount = Me.mOrderCount
        'mt.StoreID = 2
        'mt.Start()

        'Store 3
        mt = New MyThread
        MREs.Add(mt.MRE)
        mt.ConnString = Store3ConnectionString
        mt.theOrderCount = Me.gOrderCount
        mt.StoreID = 3
        mt.Start()

        'Store 4
        'mt = New MyThread
        'MREs.Add(mt.MRE)
        'mt.ConnString = Store4ConnectionString
        'mt.theOrderCount = Me.pOrderCount
        'mt.StoreID = 4
        'mt.Start()

        ManualResetEvent.WaitAll(MREs.ToArray)
        Me.Invoke(New ThreadsComplete(AddressOf ThreadsCompleted))
        If Me.TotalOrders.Text > 0 Then
            numberOfOrders = Me.TotalOrders.Text
            GetOrders()
        Else
            'Timer1.Enabled = True
        End If
    End Sub

'The myThread class - grabs and sorts the orders - displays order count results to the form
Public Class MyThread
        Private T As Thread = Nothing
        Public ConnString As String
        Public theOrderCount As Label
        Public StoreID As Integer
        Public MRE As New ManualResetEvent(False)

        Public Sub Start()
            If IsNothing(T) Then
                T = New Thread(AddressOf DoWork)
                T.Start()
            End If
        End Sub

        Public Sub DoWork()
            Dim t As Thread = Thread.CurrentThread
            Dim theText As String
            Dim sqlConn As New SqlConnection
            Dim x As Integer
            Dim da2 As SqlDataAdapter
            Dim ds2 As DataSet
            Dim tempStoreID As Integer
            Dim sql, newSQL As String

            Dim tempConn As New SqlConnection
            Dim tempcmd As New SqlCommand

            sql = "SELECT idOrder, pcOrd_Time, QB_InvoiceID, OrderStatus, StoreID From orders WHERE (QB_InvoiceID is Null or QB_InvoiceID = '') and OrderStatus = 2 ORDER by idOrder asc"

            sqlConn.ConnectionString = ConnString

            sqlConn.Open()
            da2 = New SqlDataAdapter(sql, sqlConn)
            ds2 = New DataSet()
            da2.Fill(ds2, "table5")


            If ds2.Tables(0).Rows.Count = 0 Then
                'No Order from Store
                theText = "0"
                If theOrderCount.InvokeRequired Then
                    theOrderCount.Invoke(New ChangeTextControlDelegate(AddressOf SetDisplayText), New Object() {t.Name, theOrderCount, theText})
                Else
                    SetDisplayText(t.Name, theOrderCount, theText)
                End If
            Else
                theText = (ds2.Tables(0).Rows.Count).ToString
                If theOrderCount.InvokeRequired Then
                    theOrderCount.Invoke(New ChangeTextControlDelegate(AddressOf SetDisplayText), New Object() {t.Name, theOrderCount, theText})
                Else
                    Me.SetDisplayText(t.Name, theOrderCount, theText)
                End If
                tempConn.ConnectionString = TempConnectionString
                tempConn.Open()
                For x = 0 To (ds2.Tables(0).Rows.Count - 1)
                    tempStoreID = ds2.Tables(0).Rows(x).Item("StoreID")
                    newSQL = "Insert into tempTable (StoreID,OrderID,DateTime) values (" & tempStoreID & "," & ds2.Tables(0).Rows(x).Item("idOrder") & ",'" & ds2.Tables(0).Rows(x).Item("pcOrd_Time") & "')"
                    tempcmd = New SqlCommand(newSQL, tempConn)
                    tempcmd.ExecuteNonQuery()
                Next

            End If
            sqlConn.Close()
            sqlConn.Dispose()
            da2.Dispose()
            ds2.Dispose()

            MRE.Set()

        End Sub


        Public Sub SetDisplayText(ByVal aThreadname As String, ByVal aLabel As Label, ByVal newText As String)

            aLabel.Text = newText

        End Sub
    End Class

'When Threads are done:
    Private Sub ThreadsCompleted()

        If Me.TotalOrders.InvokeRequired Then
            Dim d As New SetTextCallback(AddressOf SetText)
            Me.Invoke(d, New Object() {"Hello"})
        Else
            Me.TotalOrders.Text = (CInt(Me.hOrderCount.Text) + CInt(Me.mOrderCount.Text) + CInt(Me.gOrderCount.Text) + CInt(Me.pOrderCount.Text))
        End If

        lblOrders.ForeColor = Color.White

        DisplayOrders()

        SetText("Waiting patiently...")
    End Sub

Open in new window

0
CodeCruiserCommented:
You are starting threads at random places. Declare a List(of Thread) in your module and wherever you use a thread, add it to the list. Then you can handle the GlobalThreadException in your main form and abort all threads.
0
slightlyoffAuthor Commented:
Thanks for the help :)
0
käµfm³d 👽Commented:
NP. Glad to help  :)
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Visual Basic.NET

From novice to tech pro — start learning today.