web-dev-qa-db-ja.com

複数のアプリケーションがバッチファイルから非同期で実行されるのを待って終了します

アプリケーションの複数のインスタンスを実行する単純なWindowsバッチファイルがあります。

start app.exe param1
start app.exe param2

それらを同時に非同期で実行し(上記のように)、両方が他のアクションの実行を終了するのを待つ方法はありますか?C#のようなもの

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


/waitスイッチはここでは役に立ちません。特定のインスタンスがまだ実行されているかどうかについて、ポーリングが行われている可能性があります。

14
Jaded

この質問は、このアプリケーションがバッチスクリプトではなく.exeプロセスの終了を待機しているという点で、 並列バッチスクリプトを待機しています とは少し異なると思います。しかし、解決策はほぼ同じです。

マスターバッチスクリプトで何らかの形式のポーリングをインスタンス化する必要があります。リダイレクトを介して効果的にロックファイルを作成できます。ロックファイルは、プロセスが終了するまでロックされたままになります。バッチスクリプトがポーリングし、すべてのロックファイルを開くことができるかどうかを確認します。成功すると、すべてのプロセスが終了したことがわかります。

以下のソリューションの唯一の重要な違いは、STARTCMD /Cを介してバッチを起動するのではなく、.exeを直接起動することです。また、(call )は、常に成功するno-opを効果的に実行するための非常に高速な方法であることも学びました。そこで、remの代わりに(call )を使用しました

@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を介してプロセスを特定のCPUまたはマシンに転送する機能を備えた、並列プロセスの最大数を規制するロック技術の非常に洗練されたアプリケーションについては、 シェルプロセスの並列実行 を参照してください。その答えはまた、ロックファイル技術がどのように機能するかについてのより完全な説明を提供します。


[〜#〜]編集[〜#〜]

待機ループは、プロセスを追加するときに変更する必要がないように変更できます。

: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
21
dbenham

@dbenhamの回答に基づいて、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)。

1
ariel

別のバッチファイルでasynchBatch.batプット:

start app.exe param1
start app.exe param2

次に、呼び出し元のバッチファイルに次のように書き込みます。

call asynchBatch.bat
other executions
...

他の実行は、app.exeparam1とapp.exeparam2の両方が終了した後にのみ開始されます。

0
guys

基本的には、 [〜#〜] start [〜#〜] コマンドを使用して正しく実行します。これは、現在必要なものを対象としているためです。

さらに、この素​​晴らしい答えを参照することをお勧めします: https://stackoverflow.com/a/1449192/95231

更新:

各プログラムが終了するのを待つには、/ Wスイッチを使用してください。

start /w app.exe param1
start /w app.exe param2
0
Yair Nevet

同じapp.exeの複数のインスタンスを開始していますか?

  • それらすべてを開始します
  • ループtasklist |find "app.exe"まで%errorlevel%1
  • スクリプトを続行します
0
Stephan

Powershellには、待機ループなしでそれを行うためのより洗練された方法があります。スクリプトをPowerShellでラップまたは呼び出すことができ、C#で行うのとまったく同じようにスクリプトを実行するための優先マネージドソリューションを実装することもできます。

0
vezenkov