32

プロセスがまだ実行されているにもかかわらず、Process.HasExited時々戻ることを観察してきました。true

以下の私のコードは、「testprogram.exe」という名前のプロセスを開始し、それが終了するのを待ちます。問題は、時々例外がスローされることです。HasExitedプロセス自体がシステム内でまだ生きていることを返したとしても、trueどうしてこれができるのでしょうか?

私のプログラムは、終了する直前にログファイルに書き込むため、読み取る前に、このログファイルが存在すること(プロセスが終了/終了したこと)を絶対に確認する必要があります。その存在を継続的にチェックすることはオプションではありません。

// Create new process object
process = new Process();

// Setup event handlers
process.EnableRaisingEvents = true;
process.OutputDataReceived += OutputDataReceivedEvent;
process.ErrorDataReceived += ErrorDataReceivedEvent;
process.Exited += ProgramExitedEvent;

// Setup start info
ProcessStartInfo psi = new ProcessStartInfo
                           {
                               FileName = ExePath,
                               // Must be false to redirect IO
                               UseShellExecute = false,
                               RedirectStandardOutput = true,
                               RedirectStandardError = true,
                               Arguments = arguments
                           };

process.StartInfo = psi;

// Start the program
process.Start();

while (!process.HasExited)
    Thread.Sleep( 500 );

Process[] p = Process.GetProcessesByName( "testprogram" );

if ( p.Length != 0 )
    throw new Exception("Oh oh");

process.WaitForExit()更新:ポーリングループの代わりに待機しようとしましたが、結果はまったく同じです。

追加:上記のコードは、「より明確な」問題を同様に示すためだけのものでした。明確にするために; 私の問題は、それがtrueProcess.GetProcessesByName( "testprogram" );に設定された後でも、プロセスを保持できるということではありません。HasExited

本当の問題は、私が外部で実行しているプログラムが、ファイルを(正常に)終了する直前に書き込むことです。私HasExitedはプロセスがいつ終了したかをチェックするために使用し、ファイルを読み取ることができることを知っています(プロセスが終了したためです!)が、プログラムがまだファイルをディスクに書き込んでいない場合でもHasExited戻るようです。true正確な問題を説明するサンプルコードは次のとおりです。

// Start the program
process.Start();

while (!process.HasExited)
    Thread.Sleep( 500 );
// Could also be process.WaitForExit(), makes no difference to the result

// Now the process has quit, I can read the file it has exported
if ( !File.Exists( xmlFile ) )
{
    // But this exception is thrown occasionally, why?
    throw new Exception("xml file not found");
}
4

11 に答える 11

15

これは古い投稿であることは承知していますが、アプリが開く前にアプリが終了イベントを実行している理由を突き止めるための探求の中で、将来この問題を経験する人々に役立つかもしれない何かを見つけました.

プロセスが開始されると、PID が割り当てられます。その後、ユーザーが [ユーザー アカウント制御] ダイアログでプロンプトを表示され、[はい] を選択すると、プロセスが再起動され、新しい PID が割り当てられます。

私はこれで数時間座っていました。これで誰かの時間を節約できることを願っています。

于 2014-10-22T13:11:41.550 に答える
9

この方法を試してみることをお勧めします。

process.Start();

while (!process.HasExited)
{
    // Discard cached information about the process.
    process.Refresh();

    // Just a little check!
    Console.WriteLine("Physical Memory Usage: " + process.WorkingSet64.ToString());

    Thread.Sleep(500);
}

foreach (Process current in Process.GetProcessesByName("testprogram"))
{
    if ((current.Id == process.Id) && !current.HasExited)
        throw new Exception("Oh oh!");
}

とにかく...HasExitedのMSDNページで私は次のハイライトされたメモを読んでいます:

標準出力が非同期イベントハンドラーにリダイレクトされている場合、このプロパティがtrueを返したときに、出力処理が完了しない可能性があります。非同期イベント処理が完了していることを確認するには、HasExitedをチェックする前に、パラメーターを受け取らないWaitForExit()オーバーロードを呼び出します。

すべてをリダイレクトしているので、それはどういうわけかあなたの問題に関連している可能性があります。

于 2013-01-15T15:52:38.747 に答える
7

これは古い投稿ですが、誰かを助けることができるかもしれません。
Process クラスが予期しない動作をすることがあります。プロセスが終了した場合、またはプロセスが管理者権限で実行され、プログラムにユーザー権限HasExitedしかない場合は true を返します。

しばらく前にこれに関する質問をここに投稿しましたが、満足のいく回答は得られませんでした.

于 2015-01-04T20:56:45.747 に答える
5

まず、testprogram が独自のプロセスを生成し、そのプロセスが終了するのを待たずに終了することはありませんか? ここではある種の競合状態を扱っており、testprogram は重要になる可能性があります。

2 つ目のポイントは、「このログファイルが存在することを絶対に確認する必要がある」ということです。まあ、そんなことはありません。チェックを行うと、ファイルはなくなります。これに対処する一般的な方法は、チェックするのではなく、ファイルでやりたいことをすることです。先に進み、それを読み、例外をキャッチし、物事が不安定で何も変更したくない場合は再試行してください。システムに複数のアクター (スレッドなど) がある場合、機能的な check-and-do はうまく機能しません。

たくさんのランダムなアイデアが続きます。

プロセスの完了に依存するのではなく、FileSystemWatcher を使用してみましたか?

process.Exited イベントでファイルを読み込んでみる (存在するかどうかを確認するのではなく、代わりに動作する) と、状況は改善されますか? 【いけない】

システムは正常ですか? イベントログに疑わしいものはありますか?

非常に積極的なウイルス対策ポリシーが関与する可能性はありますか?

(すべてのコードを見て、テストプログラムを調べなければ、多くのことはわかりません。)

于 2013-01-17T21:46:13.477 に答える
4

したがって、問題の根本原因をさらに調査するには、 Process Monitorを使用して実際に何が起こっているかを確認する必要があります。それを開始し、外部プログラムと独自のツールを含めて、何が起こるかを記録させます。

ログ内で、外部ツールが出力ファイルに書き込む方法と、そのファイルを開く方法を確認できます。しかし、このログ内で、これらすべてのアクセスがどの順序で発生したかを確認できます。

最初に頭に浮かんだのは、Processクラスは嘘をつかないということです。嘘をつくと、プロセスは本当になくなってしまいます。問題は、現時点ではファイルがまだ完全に利用可能ではないように見えることです。これはOSの問題だと思います。ディスクに完全に書き込まれていないキャッシュ内にファイルの一部がまだ保持されており、ツールがファイル ハンドルをフラッシュせずに終了したためです。

これを念頭に置いて、外部ツールがファイルを作成し、終了し、その後ファイルがフラッシュ/クローズされることをログ内で確認する必要があります (OS によって [ログ内でこのポイントを見つけたときにフィルターを削除する可能性があります])。

したがって、私の仮定が正しい場合、根本的な原因は変更できない外部ツールの悪い動作であり、プロセスが終了した後、タイムアウトがファイルをフラッシュするのに十分な長さであることを願っています。 / OS によって閉じられます (成功するまで、タイムアウトのあるループでファイルを開こうとする可能性があります)。

于 2013-01-16T12:36:15.997 に答える
2

2 つの可能性があります。プロセス オブジェクトはプロセスへの参照を保持し続けているため、プロセスは終了しましたが、まだ削除されていません。または、実行中のプロセスの 2 番目のインスタンスがあります。また、プロセス ID を比較して確認する必要があります。これを試して。

    ....

    // Start the program
    process.Start();


    while (!process.HasExited)
        Thread.Sleep( 500 );

    Process[] p = Process.GetProcessesByName( "testprogram" );
    if ( p.Length != 0 && p[0].Id == process.id && ! p[0].HasExited)
        throw new Exception("Oh oh");
于 2010-03-25T21:59:44.943 に答える
1

process_name.Refresh()プロセスが終了したかどうかを確認する前に使用します。Refresh()プロセスに関連するすべてのキャッシュ情報をクリアします。

于 2015-04-30T07:44:40.363 に答える
1

のMSDNドキュメントによるとHasExited.

プロセスに対してハンドルが開かれている場合、オペレーティング システムは、プロセスが終了したときにプロセス メモリを解放しますが、プロセスに関する管理情報 (ハンドル、終了コード、終了時刻など) は保持します。

おそらく関係ありませんが、注目に値します。

それが時間の 1/10 だけの問題であり、HasExited の使用状況に応じて 1 秒後にプロセスが消える場合は、HasExited チェックが機能した後に別の遅延を追加してみてください。

while (!process.HasExited)
    DoStuff();
Thread.Sleep(500);
Cleanup();

問題が解決しないかどうかを確認します。

個人的には、私は常にExited、あらゆる種類のポーリングの代わりにイベント ハンドラーを使用し、単純なカスタム ラッパーを使用System.Diagnostics.Processして、スレッド セーフ、CloseMainWindow()followedWaitForExit(timeout)と finallyの呼び出しのラップKill()、ロギングなどを処理してきましたが、問題に遭遇したことはありません。 .

于 2010-03-25T22:34:46.057 に答える
1

まず、ポーリングではなく Process.WaitForExit を使用することに問題はありますか?

とにかく、プロセスが使用可能な観点から終了することは技術的に可能ですが、ディスクキャッシュのフラッシュなどを実行している間、プロセスは一時的に存在し続けます。ログ ファイルが特に大きいか (または、ディスク書き込みで大量の操作を実行していないか)。

于 2010-03-25T21:56:16.353 に答える
1

多分問題はテストプログラムにありますか?このコードは適切にフラッシュ/クローズしますか? testprogram がファイルをディスクに書き込む場合、ファイルは少なくとも利用可能である必要があります (空かどうか)。

于 2010-04-29T08:27:52.033 に答える