# Dos: Kill parallel jobs at the same time



## prem_arvapalli (Nov 15, 2010)

I am running the bat job(main bat) and that will call the two bats parallely at the same time,
I have tried to end the job(main bat) by ctrl+c then one bat file is getting ended, but the other bat file is still running,so again I have to do the ctrl+c to end the other bat file.
So how can I kill all the bat files at the same time and also how can i program this in the main bat job so that all the parallel jobs gets ended when I use ctrl+c.

Can some body please help me on this.

Thanks in advance.


----------



## TheOutcaste (Aug 8, 2007)

You can't. You have to use CTRL+C on each one, it will only effect the program that has focus when you press the keys. And since it terminates the program, you can't check for it and have a program kill other processes.


----------



## Ent (Apr 11, 2009)

I might have an idea, but I don't know if it'll work. If you can guarantee that these batch processes will be the only instances of cmd.exe, you might be able to use the taskkill command to take out all processes with that name. You would need a fourth supervising bat if main is to continue to execute. Start the main batch file from a parent of its own with three lines:


```
@echo off
Main.bat
Taskkill /im cmd.exe /f
```
If the taskkill command doesn't execute until main is stopped by CTRL + C, it should do what you're after.


----------



## TheOutcaste (Aug 8, 2007)

Main:

```
Echo.Starting Sub1
Sub1.bat
Echo.Starting Sub2
Sub2.bat
```
*Main* will wait for *Sub1.bat* to finish before continuing. *Sub1* runs in the same command window. If you press CTRL+C while *SubX* is running, *SubX* and *Main* both are terminated, as CTRL+C terminates all processing in that command window.
*Call SubX.bat* is the same as just using *SubX.bat*
Main:

```
Echo.Starting Sub1
Start "" Sub1.bat
Echo.Starting Sub2
Start "" Sub2.bat
```
Using Start, *Sub1.bat* will be run in a separate window and *Main* will continue and start *Sub2.bat* in its own window, then continue.
Hitting CTRL+C in the *Sub1* or *Sub2* window only effects that window. The program will be stopped but their windows will remain open, so you can't monitor the tasklist to see if the window closed, as it doesn't close.
Even if it did, you have no way of determining if CTRL+C was pressed, or the program simply finished it's task.

What you can do is have each program create a flag file, then check for that file after each program window closes. If the file doesn't exist, you can assume CTRL+C was pressed and then use taskkill to end all *cmd.exe* processes that you are monitoring. For this to work, you have to press CTRL+C *and* close the window.

If you run this from a Command Prompt, start Main using *Start "" Main.bat*. Then you can keep your Command Prompt window open.
Main

```
@Echo Off
Title %~n0
SetLocal EnableDelayedExpansion
Set _S1=Sub1
Set _S2=Sub2
Set _NumSub=2
Set _MProg=Monitor
Set /A _Mon=_NumSub+1
Set _Mon=%_Mon% %~n0
:: Start Sub Programs
For /L %%I In (1,1,%_NumSub%) Do (
  If Exist "%Temp%\!_S%%I!.flag" Del "%Temp%\!_S%%I!.flag"
  Echo.Starting !_S%%I!
  Start "" "!_S%%I!.bat"
  Set _Mon=!_Mon! "!_S%%I!"
)
:: Start Monitor program
Start "" %_MProg%.cmd %_Mon%
:: Your code goes here. This For loop is just for testing
[COLOR=Blue]For /L %%I In (0,5,10000) Do Echo %%I[/COLOR]
Echo.>"%Temp%\%~n0.flag"
Exit
```
Monitor

```
@Echo Off
Title %~n0
SetLocal EnableDelayedExpansion
Set _NumSub=%*
If Not Defined _NumSub Goto :EOF
Set _NumSub=%1
Set _Count=0
:_Loop
Set /A _Count+=1
Set _S%_Count%=%~2
Shift
If Not "%~2"=="" Goto _Loop
:_Check
Set _Run=0
For /L %%I In (1,1,%_NumSub%) Do (
  For /F "Tokens=1 Delims=:" %%C In ('Tasklist /FI "ImageName eq cmd.exe" /FI "WindowTitle eq !_S%%I!"') Do (
    If /I "%%C"=="INFO" (
      If Not Exist "%Temp%\!_S%%I!.flag" Goto _CtrlC
    ) Else (
      Set /A _Run+=1
    )
  )
)
If Not %_Run%==0 Goto _Check
For /L %%I In (1,1,%_NumSub%) Do If Exist "%Temp%\!_S%%I!.flag" Del "%Temp%\!_S%%I!.flag"
EndLocal
Exit
:_CtrlC
Echo.CTRL+C Pressed
For /L %%I In (1,1,%_NumSub%) Do If Exist "%Temp%\!_S%%I!.flag" Del "%Temp%\!_S%%I!.flag"
For /L %%I In (1,1,%_NumSub%) Do TaskKill /F /IM cmd.exe /FI "WindowTitle eq !_S%%I!" /T
Exit
```
Sub1

```
@Echo Off
Title %~n0
:: Your code goes here. This For loop is just for testing
[COLOR=Blue]For /L %%I In (1,1,10000) Do Echo %%I[/COLOR]
Echo.>"%Temp%\%~n0.flag"
Exit
```
Sub2

```
@Echo Off
Title %~n0
:: Your code goes here. This For loop is just for testing
[COLOR=Blue]For /L %%I In (10000,-1,1) Do Echo %%I[/COLOR]
Echo.>"%Temp%\%~n0.flag"
Exit
```


----------



## prem_arvapalli (Nov 15, 2010)

Thankyou for the repies.. I am very poor in the dos programming, can some body tell me where exactly do I have to do the changes..

Following is the code of the main bat file..
D:\DAT\SAS\DMT\Lev1\SASMain\Data\MAMisc\MAbatch\jobs\old_Campaign_DB_Personal.bat
call D:\DAT\SAS\DMT\Lev1\SASMain\Data\MAMisc\MAbatch\jobs\Count_db_pers.bat

Following is the code for the 2 bat files..

Following is the code of the first bat file...
@setlocal
@REM *********************************************************
@REM * Rundate 'D'YYMMDD must be specified as first argument *
@REM *********************************************************
@REM *********************************************************
@REM * Command-file must exist *
@REM *********************************************************
FOR /R D:\DAT\SAS\DMT\Lev1\SASMain\Data\MAMisc\MASched\jobs\DB_Personal\ %%G IN (*.bat) DO start /b "call D:\DAT\SAS\DMT\Lev1\SASMain\Data\MAMisc\MASched\jobs\DB_Personal\" %%G

@set rc=%errorlevel%
@REM *******************************************************
@REM * Exit script and report return code *
@REM *******************************************************
:done
@echo rc=%rc%
@exit /b %rc%
@REM *******************************************************
@REM * Handle argument errors *
@REM *******************************************************
:noargument
@echo Error: No argument specified
@set rc=2
@goto done
:nopgm
@echo Error: Command file "%sch_command%" does not exist
@set rc=2
@goto done
Following is the code of the second bat file.
@echo off & setLocal enableDELAYedexpansion
set toterrors=
set totjobs=
for /f "tokens=1 delims= " %%a in (D:\DAT\SAS\DMT\Lev1\SASMain\Data\MAMisc\MASched\jobs\count\count.txt) do (
set /a toterrors+=%%a
)
for /f "tokens=2 delims= " %%b in (D:\DAT\SAS\DMT\Lev1\SASMain\Data\MAMisc\MASched\jobs\count\count.txt) do (
set /a totjobs+=%%b
)
@echo total errors is !toterrors!
@echo total jobs is !totjobs!
goto :eof


----------



## TheOutcaste (Aug 8, 2007)

Your first file uses *start /b "call* *D:\DAT\SAS*...
The */b* disables *CTRL+C* so you can't stop the batch files *old_Campaign_DB_Person al.bat* one calls.
They each start a new *cmd.exe* process, but don't open a new window, so each file will change the title of the current window. There is no way to test when a process has ended so you won't know when to check for a flag file.

You aren't using start to run *old_Campaign_DB_Person al.bat*, so *Count_db_pers.bat* won't start until the first has finished.
About all you can do is prevent *Count_db_pers.bat* from starting if *old_Campaign_DB_Person al.bat* did not complete successfully.
Have *old_Campaign_DB_Person al.bat* create a file when it's done and check for that file.

If you start with an *Echo Off* statement, you don't need the *@* symbol on each line.
All of the error checking code can be deleted, it never gets used. (unless you are adding checking later of course, or there is more to the file)
In the main file add the check for the flag file, and check the error code that it returns:

```
D:\DAT\SAS\DMT\Lev1\SASMain\Data\MAMisc\MAbatch\jobs\old_Campaign_DB_Person  al.bat
[COLOR=Red]If Errorlevel 1 Goto :EOF[/COLOR]
[COLOR=Red]If Exist "%temp%\Done.flag" Goto :EOF[/COLOR]
call D:\DAT\SAS\DMT\Lev1\SASMain\Data\MAMisc\MAbatch\jobs\Count_db_pers.bat
[COLOR=Red]If Exist "%temp%\Done.flag" Del "%temp%\Done.flag"[/COLOR]
```
Add the lines in red to create the flag file
The lines in blue never get used:

```
@Echo Off
setlocal
REM *********************************************************
REM * Rundate 'D'YYMMDD must be specified as first argument *
REM *********************************************************
REM *********************************************************
REM * Command-file must exist *
REM *********************************************************
[COLOR=Red]If Exist "%temp%\Done.flag" Del "%temp%\Done.flag"[/COLOR]
FOR /R D:\DAT\SAS\DMT\Lev1\SASMain\Data\MAMisc\MASched\jobs\DB_Personal\ %%G IN (*.bat) DO start /b "call D:\DAT\SAS\DMT\Lev1\SASMain\Data\MAMisc\MASched\jobs\DB_Personal\" %%G
set rc=%errorlevel%
REM *******************************************************
REM * Exit script and report return code *
REM *******************************************************
:done
echo rc=%rc%
[COLOR=Red]Echo.>"%temp%\Done.flag"[/COLOR]
exit /b %rc%
[COLOR=Blue]REM *******************************************************
REM * Handle argument errors *
REM *******************************************************
:noargument
echo Error: No argument specified
set rc=2
goto done
:nopgm
echo Error: Command file "%sch_command%" does not exist
set rc=2
goto done[/COLOR]
```
In the 2nd file you only need one for loop, and don't need delayed expansion:

```
@echo off
set toterrors=
set totjobs=
for /f "tokens=1,2 delims= " %%a in (D:\DAT\SAS\DMT\Lev1\SASMain\Data\MAMisc\MASched\jobs\count\count.txt) do (
set /a toterrors+=%%a
set /a totjobs+=%%b
)
echo total errors is %toterrors%
echo total jobs is %totjobs%
goto :eof
```


----------

