using(p = Process.Start(command))
Process
これは、クラスが実装するのでコンパイルされIDisposable
ますが、実際にはClose
メソッドを呼び出したいと考えています。
ロジックでは、Dispose
メソッドがユーザーを呼び出すと考えClose
られます。リフレクターを使用して CLR を掘り下げると、実際にメソッドがこれを行っていることがわかります。ここまでは順調ですね。
再びリフレクターを使用して、このClose
メソッドが何を行うかを調べました。このメソッドは、基になるネイティブの win32 プロセス ハンドルを解放し、いくつかのメンバー変数をクリアします。これ (外部リソースの解放) は、まさにIDisposable パターンが行うべきことです。
ただし、これがここで達成したいことかどうかはわかりません。
基になるハンドルを解放すると、単にウィンドウに「この他のプロセスの追跡にはもう興味がありません」と通知されます。実際に他のプロセスを終了させたり、プロセスを待機させたりすることは決してありません。
それらを強制的に終了させたい場合は、プロセスでp.Kill()
メソッドを使用する必要があります - ただし、プロセスを強制終了することは決して良い考えではありません。すぐ。
それらが自然に終了するのを待ちたい場合は、を使用できますp.WaitForExit()
- ただし、これは一度に 1 つのプロセスを待っている場合にのみ機能します。それらすべてを同時に待ちたい場合は、注意が必要です。
通常、これには を使用しますが、からオブジェクトWaitHandle.WaitAll
を取得する方法がないため、これを行うことはできません (真剣に、wtf はマイクロソフトの考えでしたか?)。WaitHandle
System.Diagnostics.Process
プロセスごとにスレッドをスピンアップし、それらのスレッドで `WaitForExit を呼び出すこともできますが、これも間違った方法です。
WaitForMultipleObjects
代わりに、p/invoke を使用してネイティブの win32関数にアクセスする必要があります。
これがサンプルです(私がテストし、実際に動作します)
[System.Runtime.InteropServices.DllImport( "kernel32.dll" )]
static extern uint WaitForMultipleObjects( uint nCount, IntPtr[] lpHandles, bool bWaitAll, uint dwMilliseconds );
static void Main( string[] args )
{
var procs = new Process[] {
Process.Start( @"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 2'" ),
Process.Start( @"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 3'" ),
Process.Start( @"C:\Program Files\ruby\bin\ruby.exe", "-e 'sleep 4'" ) };
// all started asynchronously in the background
var handles = procs.Select( p => p.Handle ).ToArray();
WaitForMultipleObjects( (uint)handles.Length, handles, true, uint.MaxValue ); // uint.maxvalue waits forever
}