[WSH] WshScriptExecオブジェクトのStdOut, StdErrプロパティを取得するときにフリーズする

1 月 7th, 2009 | Tags: , ,

MSKB英語版: Hang When Reading StdErr/StdOut Properties of WshScriptExec Object (KB960246)

対象OS

  • Windows 2000
  • Windows XP Professional
  • Windows Server 2003 Standard
  • Windows Server 2008 Enterprise

現象

WshShell.Execメソッドは、WshScriptExecオブジェクトを返します。このオブジェクトには、StdOut, StdErr プロパティがあり、Execメソッドで実行した子プロセスの標準出力・標準エラー出力へのアクセスを提供します。

しかし、このStdOut, StdErrプロパティを読み取ろうとするとき、スクリプトは固まる(フリーズ・デッドロックする)ことがあります。

原因(意訳)

  • StdOut, StdErr は、1つの4KBバッファを共有しています。
  • StdOut, StdErr は、同期的なストリームの読み込みを行います。

このような前提のもと、次のような処理を行うと問題が発生します。

  • 片方しか読み込もうとしない。StdErrで4KB書き込まれていて共有バッファがフルになっているのに、StdOutを読み込もうとしても何もデータがなくて固まってしまう。

原因(MSKB訳)

StdOut, StdErrストリームは、4KBのバッファを共有しています。また、WshScriptExecオブジェクトは、単にこのストリームを同期的に読み込む操作を行うだけです。

同期読み込み操作は、呼び出したスクリプトの読み込みと、子プロセスの書き込みに依存しています。これがデッドロック状態を起こしうるのです。

子プロセスのストリームを読み込むとき、子プロセスに依存した形になります。子プロセスがストリームに書き込むか、ストリームを閉じるまで、呼び出しは完了しません。

一方、子プロセスがストリームのバッファ(4KB)をいっぱいにしてしまうとき、親プロセスの読み込みに依存しています。

親プロセスがバッファから完全に読み込むか、ストリームを閉じるまで、子プロセスの書き込み操作は待ち状態に入って完了しません。

このようにして、スクリプトと子プロセスがお互いに読み書きを待つ状態に陥ると、デッドロック(フリーズ)が生じます。

一般的に、StdOut, StdErrの両方に書き込むようなアプリケーションで、片方しか読み込まないような処理をしていると発生します。

解決策

いくつかあります。

  1. StdOut, StdErr 両方を読み込むようにして、バッファがいっぱいにならないようにする。
  2. コンソールアプリケーションの出力をいったんファイルにリダイレクトしてから読み込む。
  3. 非同期的に読み込みができるCOMコンポーネントをつくり、これを呼び出すようにする。たとえば、Microsoft .NET Framework の System.Diagnostics.Process クラス。
TOP