VB.Net .NetCore Console Application: Main App Exits After One Process is Done

deskcheck1-0579 411 Reputation points
2021-12-04T19:10:01.787+00:00

I have multiple non-asynchronous processes that I implemented using batch files in VB.Net. The processes are supposed to be executed one after the first one (or previous process has finished)

I call the processes via batch files stored in a folder outside of VS 2019 project on a local drive.

The sample external executables are labeled:
SWAT_1008003.exe
SWAT_1008002.exe
SWAT_1001003.exe
...and so forth

However, after the first process completes, the entire application exits without error.

Here are some code snippets:

Sample Content of batch file (temp_1008003.bat) - the executable writes the output to text file.
    SWAT_10080003.exe /b 1> E:\model_run_test\10080003\SWAT.log 2>>&1

I'm using Select...Case Statement to call each Process:

Select Case priorNum
                Case 1
                    PriorityTask(huc)

                    prevProcess = "SWAT_" & huc
                    prevHuc = huc
                    my_success_path = working_folder & huc & "\success.fin"

                    If File.Exists(my_success_path) = True Then
                        Console.WriteLine("  Priority1 " & huc & " Finished: {0}", $"{DateTime.Now.ToLongDateString()} {DateTime.Now.ToLongTimeString()}")
                    Else
                        Console.WriteLine("  Priority1 " & huc & " Started:  {0}", $"{DateTime.Now.ToLongDateString()} {DateTime.Now.ToLongTimeString()}")
                    End If
                Case 2
                    prev_success_path = working_folder & prevHuc & "\success.fin"
                    my_success_path = working_folder & huc & "\success.fin"

                    DoPriorityTask(huc, priorNum, prev_success_path, my_success_path)
Case 3 ...etc.

A call to the External process:

Private Sub PriorityTask(huc As String)
    Dim np As New ProcessStartInfo
    np.WorkingDirectory = working_folder & huc & "\"
    np.FileName = "cmd.exe"
    np.Arguments = "/b /c temp_" & huc & ".bat"
    np.WindowStyle = ProcessWindowStyle.Hidden

    myProcess = New Process
    myProcess = Process.Start(np)
End Sub

Called from Select...Case Statement:

Private Sub DoPriorityTask(huc As String, priorNum As Integer, prev_success_path As String, my_success_path As String)
    Dim prevProcess As String = "SWAT_" & huc

    If File.Exists(prev_success_path) = True Then
        PriorityTask(huc)

        Console.WriteLine("  Priority" & priorNum & " " & huc & " Started: {0}", $"{DateTime.Now.ToLongDateString()} {DateTime.Now.ToLongTimeString()}")
    Else
        Console.WriteLine("  Priority" & priorNum & " " & huc & " is Waiting for Priority1 to finish...")
    End If

    If File.Exists(my_success_path) = True Then
        Console.WriteLine("  Priority" & priorNum & " " & huc & " Finished: {0}", $"{DateTime.Now.ToLongDateString()} {DateTime.Now.ToLongTimeString()}")
    End If

End Sub

This is messy. I hope someone can help. Really appreciate it.

.NET CLI
.NET CLI
A cross-platform toolchain for developing, building, running, and publishing .NET applications.
323 questions
.NET Runtime
.NET Runtime
.NET: Microsoft Technologies based on the .NET software framework.Runtime: An environment required to run apps that aren't compiled to machine language.
1,125 questions
{count} votes

Accepted answer
  1. deskcheck1-0579 411 Reputation points
    2021-12-07T18:22:12.163+00:00

    Hi y'all,

    After much research, I finally figured threads out.

    Once all the threads finished executing their tasks, the main thread/app which called them also exits. There is nothing you can do to keep them running. I tried using ThreadPool at first. Then abandoned this because:

    -No control over order of threads
    -Exits main application as soon as one thread starts
    -EventHandlers are not triggered unless asynchronous
    -Difficult to get status of threads

    Then I tried Parallel..For loops and also abandoned this because:

    • No guarantee that resource would be available; sometimes freezes while waiting for resources
    • Difficult to get status of threads

    My solution was to get rid of the batch files and used arrays of Threads. In lieu of batch files, I used the ProcessStartInfo options to redirect output and errors to a text file.
    I also used parameterized delegates to get the threads running for each group.

    For those who may be interested, here's some code snippets:

    Private Sub RunAllModels()
        'Create run priority list for all models
       Dim allDepths As List(Of PriorityDepth) = Huc8ToPriorityDepth(hucfile)  'hucfile = HUC8_Test.csv
       Dim allModels As List(Of PriorityModel) = PriorityModelList(allDepths)
    
       groupList = PriorityStringList(allDepths)   'global variable of 33 priority groups
    
       'Run Priority2 models--------------------------------------------
       Console.WriteLine("  Loading Priority2 Models:  " & $"{DateTime.Now.ToLongTimeString()}" & vbCrLf)
       'Create an array of Threads
       Dim array2 As Thread() = New Thread(groupList(1).Count - 1) {}
       For i As Integer = 0 To groupList(1).Count - 1
            Dim huc2 = groupList(1)(i)
    
            array2(i) = New Threading.Thread(AddressOf PriorityTask2)
            array2(i).Name = String.Format("P2Thread{0}", i + 1)
            array2(i).Start(huc2)
       Next
    
      'Do the rest of priorities here....
      :
      :
      : etc.
    
    End Sub
    

    '------------------------------------------
    'Parameterized Thread Delegates here....

    Private Sub PriorityTask2(huc As String)
        Try
            Dim starttime = DateTime.Now
            Dim swatexe_path = working_folder & huc & "\SWAT_" & huc & ".exe"
            Dim swat_log_path = working_folder & huc & "\SWAT.log"
            Dim mysuccess_path = working_folder & huc & "\success.fin"
            Dim num As Integer = 2                                        '!Important!
    
            Dim pi As New ProcessStartInfo
            pi.WorkingDirectory = working_folder & huc
            pi.FileName = swatexe_path
            pi.UseShellExecute = False
            pi.ErrorDialog = False
            pi.RedirectStandardOutput = True
            pi.RedirectStandardError = True
            pi.WindowStyle = ProcessWindowStyle.Hidden
    
            process2 = New Process                                         '!Important!
            process2 = Process.Start(pi)                                   '!Important!
    
            '-------Read SWAT executable output-------------------------------------
            Console.WriteLine("  Reading Priority" & num & " " & huc & " SWAT output. This could take a while...")
            Dim output As String = process2.StandardOutput.ReadToEnd()    '!Important!
            process2.WaitForExit()   'Avoid deadlock                      '!Important!
    
            '-------Write to SWAT file---------------------------------------
            Console.WriteLine("  Writing Priority" & num & " " & huc & " output to SWAT file...")
            Dim array() As String = output.Split(vbCrLf)
            File.WriteAllLines(swat_log_path, array)
    
    
            '-----Write any error to console-------------------------------
            Dim myStreamReader = process2.StandardError                    '!Important!
            ' Read the standard error and write it to console 
            Console.WriteLine(myStreamReader.ReadLine())
    
    
            '-------Write Finished times to log file----------------------
            WriteToTargetLogFile(mysuccess_path, huc, num, starttime)
    
        Catch ex As Exception
            Console.WriteLine(vbCrLf & "  Error called from PriorityTask2: " & ex.ToString())
        End Try
    End Sub
    

    This was a real workout!

    0 comments No comments

1 additional answer

Sort by: Most helpful
  1. Bruce (SqlWork.com) 56,846 Reputation points
    2021-12-06T20:49:31.573+00:00

    I see no code to wait for the process to complete, nor any code to run a second process. as process.Start() creates a new process that runs independent of the current process, why are you using a ThreadPool?

    0 comments No comments