0

I have a series of bat files that I want to run in parallel, for example:

start program1_1.bat
start program1_2.bat
start program1_3.bat
wait until program1 finished then
start program2_1.bat
start program2_2.bat
start program2_3.bat
wait until program2 finished then
...

So far, what I've tried is this function:

:waitForFinish
set counter=0
for /f %%i in ('tasklist /NH /FI "Imagename eq cmd.exe') do set /a counter=counter+1
if counter GTR 2 Goto waitForFinish

But it just launched the first 3 bat files and stop... How can I solve this problem? Thanks,

EDIT: This is the content of program1_i.bat file:

program1.exe input_i.txt

It will run program1.exe for each input file. The same for program2_i.bat.

TP Nguyen
  • 51
  • 6
  • more info please. the current level of detail isn't clear cut. I'm assuming program1_1~program1_3 are Subprograms Of program 1, and I'm Assuming that those three subprograms run their course while Program 1 also continues to run. Is program 2 meant to start after program 1, or program 1_1,1_2,1_3 etc. Do Subprograms 1_1 ~1_3 always finish before Program 1? Is program 1 or one of the Subprograms Starting Program2? – T3RR0R Jan 14 '20 at 08:23
  • Depending on your goal, the current approach your using to monitor instances of cmd.exe may suffice if you adapt it so in program 1 it starts program 2 when IF counter==1 ( goto next ) else ( Goto waitforfinish) In other words all other instances are finished - And so on for program 3 etc – T3RR0R Jan 14 '20 at 08:29
  • @T3RR0R: I edited my question. Program1_i.bat will run program1.exe for each input_i.txt file. – TP Nguyen Jan 14 '20 at 08:32
  • @TPNguyen It's been a while since I wrote the script you used and \@aschipfl also found a mistake in it. Either check the update post or use the (much cleaner) version to achieve the same goal by Aachini [in the same thread]. Good luck! – geisterfurz007 Jan 14 '20 at 10:26
  • 1
    `if counter GTR 2` is wrong (as I already commented in the code source), it must read `if %counter% GEQ 2`! Anyway, what about this (from [this answer](https://stackoverflow.com/a/43762349)): `(start program1_1.exe & start program1_2.exe & start program1_3.exe) | pause` (or replace `pause` by `set /P "="` as described [here](https://stackoverflow.com/a/33586872))? – aschipfl Jan 14 '20 at 10:29
  • I do like the start...) | pause solution as an option, however if there is a need for the OP's subrograms to run simultaneously (given it's stated they want to run them in parallel), The solution falls short. Another tool in the box though. – T3RR0R Jan 14 '20 at 10:36

4 Answers4

1

Your question is a little vague on the exact expected results.

I am however assuming that you want to do something like this.

start /wait program1_1.bat | start /wait program1_2.bat | start /wait program1_3.bat
start /wait program2_1.bat | start /wait program2_2.bat | start /wait program2_3.bat

The single pipe separators let's us launch the first three commands in parallel and only start the next three commands once the first three has all completed, simply because the next 3 commands are in the next batch line the use of start /wait

Gerhard
  • 22,678
  • 7
  • 27
  • 43
  • 1
    This might work, though I 'd finally use `start /WAIT cmd /C program?_?.bat` in order not to leave multiple `cmd.exe` windows behind... – aschipfl Jan 15 '20 at 13:42
  • 1
    @aschipfl Exactly yes.. I never amended the code after op's answer, but as per edit in the question. I would have then moved away from creating little batch files and instead do: `start "" /wait program1.exe input_i.txt` – Gerhard Jan 15 '20 at 13:45
0

* Update * The solution provided here works nicely to achieve parallel running of subprograms without needing user entry (pause) or a fixed length Timeout between program groups.

Combined with the original answer:

@echo off

:controller

Call :launcher "program1_1.bat" "program1_2.bat" "program1_3.bat"

Call :launcher "program2_1.bat" "program2_2.bat" "program2_3.bat"

pause
EXIT

:launcher
For %%a in (%*) Do (
Start "+++batch+++" "%%~a"
)

:loop
    timeout /t 1 >nul
    tasklist /fi "windowtitle eq +++batch+++*" |find "cmd.exe" >nul && goto :loop

GOTO :EOF

Original Answer:

This is a simple way to ensure each group of programs is finished before the next. The fault in the tasklist method is that if there's other cmd.exe processes running, the If condition may not be true when expected, causing the script to hang.

The start /wait option is not ideal, as you intend on running multiple programs simultaneously - and if the subprogram you wait on finishes before the other subs, you're back to square 1.

@echo off

:controller

Call :launcher "program1_1.bat" "program1_2.bat" "program1_3.bat"

Call :launcher "program2_1.bat" "program2_2.bat" "program2_3.bat"

pause
EXIT

:launcher
For %%a in (%*) Do (
Start "" "%%~a"
)

pause
GOTO :EOF
T3RR0R
  • 2,747
  • 3
  • 10
  • 25
0

Ok, here is what worked for me:

@echo off
setlocal enableextensions enabledelayedexpansion
call :InitDos
start program1_1.bat
start program1_2.bat
start program1_3.bat
call :waitForFinish
start program2_1.bat
start program2_2.bat
start program2_3.bat
call :waitForFinish
Goto:eof
: waitForFinish
set /a counter=0
for /f %%i in ('tasklist /NH /FI "Imagename eq cmd.exe"') do (
    set /a counter+=1
)
if !counter! GTR !init_count! Goto waitForFinish
goto :eof
: InitDos
set /a init_count=0
for /f %%i in ('tasklist /NH /FI "Imagename eq cmd.exe"') do (
    set /a init_count+=1
)
goto :eof
TP Nguyen
  • 51
  • 6
  • 1
    Why relying on `cmd.exe` (another command line window might be started in between)? Just give your started processes a title `start "MySubProc" program1_1.bat` and count them with `for /f %%i in ('tasklist /fi "windowtitle eq MySubProc" /nh |find /c "Console"') do set counter=%%i`, so you get only the relevant processes. – Stephan Jan 14 '20 at 16:28
-3

Try /WAIT switch on start command. I guess if you wrap bats into script called with wait switch, it could work.

Tomáš Záluský
  • 10,735
  • 2
  • 36
  • 64