Подождите, пока несколько приложений будут выполняться асинхронно из пакетного файла для завершения

Существует простой пакетный файл Windows, который запускает несколько экземпляров приложения:

start app.exe param1
start app.exe param2

Есть ли способ запускать их асинхронно в одно и то же время (что выше) и ждать, пока они оба закончат выполнение других действий - что-то вроде С#

Task.WhenAll(tasksList.ToArray());
/* Process tasksList.Result */

?
/wait switch не поможет здесь, некоторые опросы, если конкретный экземпляр все еще работает.

Ответ 1

Я предполагаю, что этот вопрос немного отличается от Ожидание параллельных пакетных скриптов в том, что это приложение ожидает завершения процессов .exe вместо пакетных скриптов. Но решение почти идентично.

Вы должны создать экземпляр какой-либо формы опроса в своей мастер-партии script. Вы можете эффективно создать файл блокировки с помощью перенаправления. Файл блокировки остается заблокированным до тех пор, пока процесс не завершится. Ваш пакетный опрос script, проверяя, может ли он открыть все файлы блокировки. Как только он преуспеет, он знает, что все процессы завершены.

Единственное существенное отличие в приведенном ниже решении состоит в том, что START запускает .exe напрямую, а не запускает пакет через CMD /C. Я также узнал, что (call ) - это чрезвычайно быстрый способ эффективно выполнять no-op, который всегда преуспевает. Поэтому я заменил (call ) вместо rem

@echo off
setlocal
set "lock=%temp%\wait%random%.lock"

:: Launch processes asynchronously, with stream 9 redirected to a lock file.
:: The lock file will remain locked until the script ends.
start "" 9>"%lock%1" notepad.exe
start "" 9>"%lock%2" notepad.exe

:Wait for both processes to finish (wait until lock files are no longer locked)
1>nul 2>nul ping /n 2 ::1
for %%N in (1 2) do (
  (call ) 9>"%lock%%%N" || goto :Wait
) 2>nul

::delete the lock files
del "%lock%*"

:: Finish up
echo Done - ready to continue processing

См. Параллельное выполнение процессов оболочки для довольно сложного применения технологии блокировки, которая регулирует максимальное количество параллельных процессов, с возможностью прямого управления процессами с конкретными процессорами или машины через PSEXEC. Этот ответ также дает более полное объяснение того, как работает технология блокировки файлов.


ИЗМЕНИТЬ

Цикл ожидания может быть изменен так, чтобы он не изменялся при добавлении дополнительных процессов:

:Wait for all processes to finish (wait until lock files are no longer locked)
1>nul 2>nul ping /n 2 ::1
for %%F in ("%lock%*") do (
  (call ) 9>"%%F" || goto :Wait
) 2>nul

Ответ 2

Адаптация к @dbenham answer, вот как я заставил ее работать внутри for и для неограниченного количества процессов:

setlocal enabledelayedexpansion
for %%a in (*.*) do start "" 9>"%temp%/wait!random!.lock" /b /low "myprogram.exe" -program_parameters

:wait
ping /n 2 ::1 > nul
echo waiting processes to finish...
2>nul del "%temp%\wait*.lock" > nul
if exist "%temp%\wait*.lock" goto :wait

... more commands ...

Здесь %random% не работает, потому что он расширяется при вызове for, поэтому все номера одинаковы. Итак, я enabledelayedexpansion и использую !random!.

В цикле я пытаюсь удалить все файлы. 2>nul убедитесь, что на экране не появится какая-либо ошибка. Это произойдет только тогда, когда все можно будет удалить (if exist).

Ответ 3

В принципе, вы делаете это правильно, используя команду START, потому что она предназначена для того, что вам нужно сейчас.

Кроме того, я предлагаю вам обратиться к этому замечательному ответу: fooobar.com/questions/42340/...

UPDATE:

Для ожидания завершения каждой программы используйте переключатель /W, посмотрите:

start /w app.exe param1
start /w app.exe param2

Ответ 4

Вы запускаете несколько экземпляров одного и того же app.exe?

  • запустите их все
  • loop tasklist |find "app.exe" до %errorlevel% 1
  • продолжайте работу с script

Ответ 5

Powershell имеет более сложные способы сделать это без циклов ожидания. Вы можете обернуть или вызвать свои сценарии с помощью PowerShell и даже реализовать свои предпочтительные управляемые решения, чтобы сделать это именно так, как вы делаете это на С#.

Ответ 6

В отдельном командном файле asynchBatch.bat put:

start app.exe param1
start app.exe param2

Затем в пакетном файле вызывающего абонента напишите:

call asynchBatch.bat
other executions
...

Другие исполнения будут запускаться только после завершения параметров app.exe param1 и app.exe param2.