How to keep shells from executing on top of each other

Hello All,

I have a console program calling a series of other console programs (they are all Xojo).
I thought I would try a loop to check for when the shell was finished, but that doesn’t seem to be doing it and each command gets executed one after another without any pause and changing the mode doesn’t make any difference that I can tell.

Ideally I would like them all running and then go back to the top of the loop and run again. But I am OK with them running serially.
Any thoughts on how to do this?

For i = 0 to arrToDo.Ubound

    Do Until DoneFlag = "YES"
       If ExtractFolder.Exists then
           DeleteTargetDir()
       Else
          DoneFlag = "YES"
       End If
    Loop
sh.Mode = 0
sh.Execute("E:\\bin\\mcunzip\\mcunzip.exe -s E:\\110901\\exported_data\" + arrToDo(i) + " -t E:\\folder1\\folder2\\extracts")
sh.Execute("E:\\bin\\mcbounces\\mcbounces.exe -m " + PgmMode)
sh.Execute("E:\\bin\\mcclicks\\mcclicks.exe -m " + PgmMode)
sh.Execute("E:\\bin\\mccomplaints\\mccomplaints.exe -m " + PgmMode)
sh.Execute("E:\\bin\\mclistmembership\\listmembership.exe -m " + PgmMode)
DoneFlag = "NO"
ShellRunning = "YES"

Do Until ShellRunning = "NO"
    If sh.IsRunning then
        ShellRunning = "YES"
    Else
        ShellRunning = "NO"
    End If
Loop

Next i

Thanks.

A few things…

First, on Windows, I believe you have to be aware of the Timeout property. It may be that your shell is exiting prematurely.

Second, you aren’t checking for an error, so perhaps your shell isn’t doing what you think it is?

Third, with mode = 0, the shell will execute its command before returning control to your app. By definition, it’s “done” when your program reaches the next line of code so you have no need for the whole “ShellRunning” apparatus.

If you want them running in parallel, create a shell object for each command, add them to an array, set their modes to 1, Execute, and then check each one until they are all done. Be sure to call either sh.Poll on each or App.DoEvents in the loop to give them time to finish and update their status.

Alternatively, you can create a Shell subclass that re-runs itself when complete, but that’s probably a topic for another day.

You may also create a batch file and use it with a single shell call.

Not for parallel processing though, right?

Oops. I missed that…

No biggie as Craig said he could go either way. I was just clarifying.

Hi @Kem Tekinay and @Thomas Eckert ,

Thanks to both of you for the excellent suggestions.

Kem ~ I think you might actually sleep less than I do… :slight_smile:

I will play with you suggestions and let you guys know how it goes.
As always I really appreciate the responses ~ I LOVE the Xojo community!

As Kem mentioned, be sure to set the sh.Timeout value to -1 or Windows will kill your task if it takes longer than 2 seconds.

Make DoneFlag a Boolean and try you code this way:

For i = 0 to arrToDo.Ubound Do Until DoneFlag If ExtractFolder.Exists then DeleteTargetDir() Else DoneFlag = True End If Loop sh.Mode = 1 sh.TimeOut = -1 sh.Execute("E:\\bin\\mcunzip\\mcunzip.exe -s E:\\110901\\exported_data\" + arrToDo(i) + " -t E:\\folder1\\folder2\\extracts") Do sh.Poll App.DoEvents(2) Loop Until Not sh.IsRunning If sh.ErrorCode <> 0 Then // Handle error or build error stack End If sh.Execute("E:\\bin\\mcbounces\\mcbounces.exe -m " + PgmMode) Do sh.Poll App.DoEvents(2) Loop Until Not sh.IsRunning If sh.ErrorCode <> 0 Then // Handle error or add to error stack End If sh.Execute("E:\\bin\\mcclicks\\mcclicks.exe -m " + PgmMode) Do sh.Poll App.DoEvents(2) Loop Until Not sh.IsRunning If sh.ErrorCode <> 0 Then // Handle error or add to error stack End If sh.Execute("E:\\bin\\mccomplaints\\mccomplaints.exe -m " + PgmMode) Do sh.Poll App.DoEvents(2) Loop Until Not sh.IsRunning If sh.ErrorCode <> 0 Then // Handle error or add to error stack End If sh.Execute("E:\\bin\\mclistmembership\\listmembership.exe -m " + PgmMode) Do sh.Poll App.DoEvents(2) Loop Until Not sh.IsRunning If sh.ErrorCode <> 0 Then // Handle error or add to error stack End If // if you created an error stack, handle the error events here DoneFlag = False Next i

@Tim Jones , why even use Mode = 1 instead of 0 in that case?

Because mode 0 blocks and causes the console app to zoom in CPU utilization unnecessarily.

Also, note that the Windows timer minimum is 14-15ms, but using 2 seems to force the loop to stay very tight on recognizing the completion of the shell process.

Thanks.

What about starting each Shell, adding it to an array, then looping through the array to remove the ones that are done? When the array is empty, they are all done and we can move on. This would have the advantage of using multiple processors.

Hi All,

Kem was right that the problem I was having was that the shell was timing out.
And then there were all the other answers and the discussion.
Thanks @Tim Jones for the code and the explanations.