.netのスレッドモデルは初めてです。何に使用しますか:
この操作はアプリケーションに影響を与えないため、プロセスの開始と待機はメインスレッドとは異なるスレッドで実行する必要があります。
例:
私のアプリケーションはhtmlレポートを作成します。ユーザーはどこかを右クリックして「レポートを表示」と言うことができます-今、レポートの内容を一時ファイルで取得し、htmlファイルを処理するプロセス、つまりデフォルトのブラウザーを起動します。問題は、クリーンアップ、つまり一時ファイルを削除できないことです。
「そして、待つことは非同期でなければならない」-私はおかしくなろうとはしていませんが、それは用語の矛盾ではありませんか?ただし、Process
を開始しているので、Exited
イベントが役立ちます。
ProcessStartInfo startInfo = null;
Process process = Process.Start(startInfo);
process.EnableRaisingEvents = true;
process.Exited += delegate {/* clean up*/};
実際に待機する場合(タイムアウトなど)、次のようにします。
if(process.WaitForExit(timeout)) {
// user exited
} else {
// timeout (perhaps process.Kill();)
}
非同期を待機するには、おそらく別のスレッドを使用しますか?
ThreadPool.QueueUserWorkItem(delegate {
Process process = Process.Start(startInfo);
if(process.WaitForExit(timeout)) {
// user exited
} else {
// timeout
}
});
この古い質問に対する高度な代替案を追加します。スレッドをブロックせずにプロセスが終了するのを待ち、それでもタイムアウトをサポートしたい場合は、次を試してください:
public static Task<bool> WaitForExitAsync(this Process process, TimeSpan timeout)
{
ManualResetEvent processWaitObject = new ManualResetEvent(false);
processWaitObject.SafeWaitHandle = new SafeWaitHandle(process.Handle, false);
TaskCompletionSource<bool> tcs = new TaskCompletionSource<bool>();
RegisteredWaitHandle registeredProcessWaitHandle = null;
registeredProcessWaitHandle = ThreadPool.RegisterWaitForSingleObject(
processWaitObject,
delegate(object state, bool timedOut)
{
if (!timedOut)
{
registeredProcessWaitHandle.Unregister(null);
}
processWaitObject.Dispose();
tcs.SetResult(!timedOut);
},
null /* state */,
timeout,
true /* executeOnlyOnce */);
return tcs.Task;
}
繰り返しますが、受け入れられた答えと比較したこのアプローチの利点は、スレッドをブロックしないことです。これにより、アプリのオーバーヘッドが削減されます。
次のコードを試してください。
public void KickOffProcess(string filePath) {
var proc = Process.Start(filePath);
ThreadPool.QueueUserWorkItem(new WaitCallBack(WaitForProc), proc);
}
private void WaitForProc(object obj) {
var proc = (Process)obj;
proc.WaitForExit();
// Do the file deletion here
}
ファイルを開くために別のプロセスを使用することはおそらくないでしょう。代わりに、おそらくバックグラウンドスレッドを使用します(操作に時間がかかり、UIスレッドがブロックされる可能性があると考えた場合)。
private delegate void FileOpenDelegate(string filename);
public void OpenFile(string filename)
{
FileOpenDelegate fileOpenDelegate = OpenFileAsync;
AsyncCallback callback = AsyncCompleteMethod;
fileOpenDelegate.BeginInvoke(filename, callback, state);
}
private void OpenFileAsync(string filename)
{
// file opening code here, and then do whatever with the file
}
もちろん、これは良い動作例ではなく(何も返さない)、UIの更新方法は示していません(バックグラウンドスレッドではUIスレッドを更新できないため、UIレベルでBeginInvokeを使用する必要があります)。しかし、このアプローチは、一般的に.Netで非同期操作を処理する方法です。
ProcessクラスでExited
イベントを使用できます
ProcessStartInfo info = new ProcessStartInfo();
info.FileName = "notepad.exe";
Process process = Process.Start(info);
process.Exited += new EventHandler(process_Exited);
Console.Read();
そのイベントでは、あなたが言及した操作を処理できます