November 04, 2004

System.Diagnostics.Processで外部exeを叩いたときになんか知らないけどデッドロックしたりしなかったりする件について

Posted at November 4, 2004 03:02 AM in .

ええと。.NETプログラミングのお話。Processを使って外部のexeファイルを叩いて処理を実行させ、その結果を標準出力経由で受け取るコードを書いていたのだが、何だか知らないけどたまにデッドロックする。具体的にはProcess.HasExitedがfalseを返し、Process.Respondingがtrueを返すという状態になる。

Process.WaitForExitの引数にミリ秒単位でタイムアウトまでの時間を設定することができるのでとりあえずこれに適当な時間を指定しておき、あとは

if ( !process.HasExited )
{
	if ( process.Responding )
		process.CloseMainWindow();
	else
		process.Kill();
}

とかやってうさんくさい後始末をしていたのだがこれは余計な待ち時間が入るので能率が悪い。これでも標準出力の結果はどうもきちんと取れているっぽいのだが。

結局MicrosoftのMSDNで解決策が見つかった。

Process.StandardOutput プロパティ
http://www.microsoft.com/japan/msdn/library/default.asp?
url=/japan/msdn/library/ja/cpref/html/frlrfsystemdiagnosti
csprocessclassstandardoutputtopic.asp

Process コンポーネントは、パイプを使用して子プロセスと通信します。子プロセスからパイプに書き込まれるデータによってバッファが満杯になる場合は、親プロセスがパイプからデータを読み取るまで、子プロセスがブロックされます。アプリケーションが、標準エラー出力および標準出力へのすべての出力を読み取る場合、このブロック処理がデッドロックの原因になることがあります。

左様で御座いましたか。これを反映して、手元のコードでは、Processを使ってexeを叩くあたりのコードはこんな感じになった。

Process process = new Process();
process.StartInfo.FileName = commandname;
process.StartInfo.Arguments = arguments;
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
process.StartInfo.RedirectStandardOutput = true;
process.StartInfo.WorkingDirectory = JSPIDER_PATH;
process.Start();
temp = process.StandardOutput.ReadToEnd();
process.WaitForExit(1200000); //wait 20 minites
temp += process.StandardOutput.ReadToEnd();

やり方が分かれば何てことないバグだが、半日くらい潰してしまった。



Trackback

You can ping this entry by using http://windy.ac/MT/mt-tb.cgi/609 .

Comments

Post a comment










Remember personal info?