トップ «前の日記(2011-03-19) 最新 次の日記(2011-03-24)» 編集

日々の破片

Subscribe with livedoor Reader
著作一覧

2011-03-23

_ アプリケーション死すともプロセス死せず

CPUが早くなって、しかもコア数が増えて同時実行可能なプロセス数が増えると、考えもしないタイミングが生まれる。

GetExitCodeProcess APIは、"If the process has terminated and the function succeeds, the termination status returned may be one of the following"だから、プロセスは現在完了形でターミネートしていて、呼び出しに成功したらステータスが返る。ということはプロセスはターミネートしているはずだ。

でも、どうもそうではない。というのは、ロジカルに特定のプロセスがCDしているディレクトリが、そのプロセスがターミネートした(追記:と、上のようにGetExitCodeProcess呼び出しの結果から判断した)にもかかわらずアクセス中のプロセスが存在して消せないという状態になることがあるからだ。

ExitProcess APIの説明を読むと、Exiting a process causes the following:として、

1. プロセスがオープンしたすべてのオブジェクトハンドルをクローズする

2. 呼び出したスレッド意外のすべてのプロセス内のスレッドの実行がターミネートする。 DLLのDLL_PROCESS_DETACHを呼び出す。

3. プロセスオブジェクトはシグナル状態になる。

4. すべてのスレッドがシグナル状態になる。

5. プロセス状態はSTILL_ACTIVEから終了値に変わる

と書いてあるから、プロセスハンドルがシグナルになるのは3でGetExitCodeProcess呼び出しより前に思える。だが、この数字は単なるドットの意味しかないとしたらどうだろうか?

Terminating a Processの章には次の記述がある。

"When a process terminates, its termination status changes from STILL_ACTIVE to the exit code of the process.

When a process terminates, the state of the process object becomes signaled, releasing any threads that had been waiting for the process to terminate. For more about synchronization, see Synchronizing Execution of Multiple Threads."

この順で処理されるとしたら、まず終了ステータスがSTILL_ACTIVEから退出コードに変更される。次に、プロセスオブジェクトがシグナル状態になる。

CPUが高速で、同時に実行できるプロセスが2つ以上あれば、上記の文章がその順序に発生するとしたら、ちょうど改行の位置でGetExitCodeProcessを呼び出すことが可能だ。

これは結構おそろしい。つまり、他のプロセス(や他のスレッド)に対して自分の状態変化を複数の状態変数を通して教える場合、その順序は厳密に文書化しなければならないし(したがって、MSDNのTerminating a Process(多分正しい順序)と、ExitProcess(多分正しくない順序)のように矛盾があってはならない)、逆に教えられる側は、その順序を守るか、さもなければすべての状態変数の確認をしなければならないということだ。

大変な時代に突入したものだ。

追記:コメント欄のNyaRuRuさんの他のプロセスの介入の可能性という指摘は確かにあるので(今回の僕のケースだとちょっと考えにくいけど)、可能性いろいろということで。(すると結論は、ソースが読めないOSでは、微妙なタイミングの処理を正しく記述することは不可能というような方向になったりするのかも知れない)

本日のツッコミ(全2件) [ツッコミを入れる]
_ NyaRuRu (2011-03-23 17:55)

私も,ビルドサーバ上で起こる不可解なファイルアクセス競合でビルドが失敗するという現象はたびたび目にしてきているので,この手の現象の厄介さやよく分かります.その上で,一点気になったので.<br><br>"ロジカルに特定のプロセスがCDしているディレクトリが、そのプロセスがターミネートしたにもかかわらずアクセス中のプロセスが存在して消せないという状態になることがあるからだ。"<br>ゆえに<br>"どうもそうではない。"<br>というロジックだと読みました.<br>確かに,単純にプロセスがターミネートしていないタイミングがあるというシナリオでも説明できるかもしれません.<br>しかし,現在のWindows は,多数の常駐プロセス (シェル,アンチウィルスソフト,インデックスエンジン,etc) が並行して動いており,ファイル操作で競合を起こした「アクセス中のプロセス」というのが,本当に元のプロセスと同一かどうかについても検討する必要があるかもしれません.<br><br>Windows で,プロセス A がロックしていたファイルリソースを,プロセス A の終了直後にプロセス B が引き継げるようにしたいがどうするか? というテーマは割と面白いと思います.<br>もっとも,ビルド等なら,適当にウェイトを入れつつ数回リトライでお茶を濁すことが多いですが.<br><br>あと今回の件とは直接は関係ありませんが,以下のバグハンティングもファイルアクセス競合に関する読み物として面白かったです.<br>ご参考までに.<br>http://technet.microsoft.com/ja-jp/windows/ff363108

_ arton (2011-03-23 20:41)

ああ、確かに> 単純に元のプロセスと同一かどうか<br>言われてみれば、ウィルス検出ソフトをディスエーブルしたら通ったという例を聞いたことありますね。<br>したがって、GetExitCodeProcessだけで判断してはだめなのがプロセスハンドルのWaitを追加すると解消する=実は単に待ち時間が増加して結果オーライという可能性もあり得ると思います。


2003|06|07|08|09|10|11|12|
2004|01|02|03|04|05|06|07|08|09|10|11|12|
2005|01|02|03|04|05|06|07|08|09|10|11|12|
2006|01|02|03|04|05|06|07|08|09|10|11|12|
2007|01|02|03|04|05|06|07|08|09|10|11|12|
2008|01|02|03|04|05|06|07|08|09|10|11|12|
2009|01|02|03|04|05|06|07|08|09|10|11|12|
2010|01|02|03|04|05|06|07|08|09|10|11|12|
2011|01|02|03|04|05|06|07|08|09|10|11|12|
2012|01|02|03|04|05|06|07|08|09|10|11|12|
2013|01|02|03|04|05|06|07|08|09|10|11|12|
2014|01|02|03|04|05|06|07|08|09|10|11|12|
2015|01|02|03|04|05|06|07|08|09|10|11|12|
2016|01|02|03|04|05|06|07|08|09|10|11|12|
2017|01|02|03|04|05|06|07|08|09|10|11|12|
2018|01|02|03|04|05|06|07|08|09|10|11|

ジェズイットを見習え