Подтвердить что ты не робот

Как создать несколько процессов из оболочки Windows и дождаться завершения их?

Я хочу сделать следующее из пакета Windows script:

start proc1.exe

start proc2.exe

...

start procN.exe

<wait for all N processes to complete> <-- What do I put here?

Как мне ждать завершения всех порожденных процессов?

4b9b3361

Ответ 1

Это некрасиво, но вы можете обернуть каждую команду в другой пакетный файл, который запускает команду, а затем сигнализирует о завершении команды. Ваш основной пакетный файл будет асинхронно вызывать каждый из этих пакетных файлов и сидеть в петле, ожидающей сигналов.

Например:

main.bat

start cmd /c proc1.bat
start cmd /c proc2.bat
:wait
sleep 1
IF NOT EXIST proc1done GOTO wait
IF NOT EXIST proc2done GOTO wait
del proc1done
del proc2done
echo All processes are complete

proc1.bat

proc1.exe
echo Done > proc1done

Команда sleep доступна в Windows Kit 2003 Resource Kit Tools. Если у вас этого нет, вы можете использовать ping на localhost, чтобы замедлить этот жесткий цикл.

Ответ 2

Это можно сделать, если вы пишете код .NET или код Win32 C/С++ для запуска процессов, но нет способа сделать это в пакетном файле. Когда вы используете start, чтобы make proc.exe выполнялся асинхронно, нет пакетной команды, которая позволяет вам вернуться позже и дождаться завершения.

Но вы можете сделать это легко на одном из языков сценариев, предназначенных для пакетной работы, Python, WSH и т.д.

Например, здесь простой script с использованием Windows script Host. WSH входит во все версии Windows с Windows 98. Таким образом, этот script должен работать где угодно.

Этот script запускает две программы и ждет их завершения. Сохраните его как start2.wsf. Затем просто используйте его в своем пакетном файле:

start2.wsf "prog1.exe" "prog2.exe"


<package>
  <job id="Start 2 Procs">
    <runtime>
      <description>Start 2 programs and wait for them both to finish.
      </description>
      <unnamed
        name="program"
        helpstring="the program to run"
        many="false"
        required="2"
      />
      <example>
        Example: Start2.wsf "cl -c foo.obj" "cl -c bar.obj"
      </example>
    </runtime>

    <script language="JScript">

      if (WScript.Arguments.length < 2)
      {
        WScript.Arguments.ShowUsage();
        WScript.Quit();
      }

      var proc1 = WScript.Arguments.Unnamed.Item(0);
      var proc2 = WScript.Arguments.Unnamed.Item(1);

      var Shell = WScript.CreateObject("WScript.Shell");
      var oProc1 = Shell.Exec(proc1);
      var oProc2 = Shell.Exec(proc2);

      while (oProc1.Status == 0 && oProc2.Status == 0)
      {
        WScript.Sleep(1000);
      }
    </script>
  </job>
</package>

Ответ 3

Как правило, вы делаете что-то подобное с помощью Python, но здесь это происходит (вдохновлено этим сообщением и другими):

calcFromList.bat < DesiredBatchFile > < TxtFile > [--async [SleepTimeBetweenSpawns]]

Он будет порождать один процесс для каждой строки в TxtFile (строка используется для указания отдельных параметров для пакетного файла).

calcFromList.bat:

echo off

pushd \
%~d0
cd "%~dp0"

set CALL_BAT="%~1"
set FILE_CONTAINING_LIST="%~2"

if %CALL_BAT%=="" (goto badval)
if %FILE_CONTAINING_LIST%=="" (goto badval2)

if "%3"=="--async" goto async

for /f "delims=¬" %%X in ('type %FILE_CONTAINING_LIST%') do (call %CALL_BAT% %%X)
goto end

:async
set /a AsyncCountNum=1

set SLEEP_VALUE_S=0

if not "%4"=="" (set SLEEP_VALUE_S=%4)
set AsyncParamBat=%CALL_BAT%

:: Find unique id even if called simultaneously (using simple collision detection)
:newid
timeout /t 1 /nobreak > NUL
set AsyncRand=%RANDOM:~-1%%RANDOM:~-2%%RANDOM:~-3%
set AsyncCountFilePrefix="%FILE_CONTAINING_LIST:"=%__%AsyncRand%"
set AsyncCollisionText="%~1;%~2;%~3;%~4;"
IF EXIST "%AsyncCountFilePrefix:"=%0" GOTO newid
echo %AsyncCollisionText% > "%AsyncCountFilePrefix:"=%_init_async_done.txt"
set /p AsyncCheckColision=<"%AsyncCountFilePrefix:"=%_init_async_done.txt"

if "%AsyncCollisionText:"=% "=="%AsyncCheckColision:"=%" GOTO idfound
timeout /t 1 /nobreak > NUL
GOTO newid
:idfound

echo Beginning spawning of processes (id = %AsyncRand%)...

for /f "delims=¬" %%X in ('type %FILE_CONTAINING_LIST%') do (set AsyncParamCall="%%~X" & start "Batch (from id %AsyncRand%)" /D "%~dp0" "cmd /c asyncExec.bat" & set /a AsyncCountNum+=1 & timeout /t %SLEEP_VALUE_S% /nobreak > NUL)

set /a AsyncCountNum-=1
echo All %AsyncCountNum% processes spawned, waiting for their completion...
:wait
timeout /t 2 /nobreak > NUL
for /l %%x in (1, 1, %AsyncCountNum%) do (IF NOT EXIST "%AsyncCountFilePrefix:"=%_%%x_tmp_async_done.txt" GOTO wait )

echo Finished, cleaning up...
for /l %%x in (1, 1, %AsyncCountNum%) do (del /F /Q  "%AsyncCountFilePrefix:"=%_%%x_tmp_async_done.txt")
del /F /Q "%AsyncCountFilePrefix:"=%_init_async_done.txt"
goto end

start "Calib for %~TARGET_FOLDER%" /D "%~dp0" "cmd /k calibCamsSequence.bat"

goto end
:badval
echo No bat file specified! (first parameter)

goto end
:badval2
echo No list file specified! (second parameter)

:end
popd

asyncExec.bat:

@call %AsyncParamBat% %AsyncParamCall%
@echo "Done at %DATE% %TIME%" > "%AsyncCountFilePrefix:"=%_%AsyncCountNum%_tmp_async_done.txt"