紅'と申します。
ミューテクスの排他制御について教えてください。
開発環境は WinXP & VC2003 です。
CreateMutex で作成したハンドルを元に、WaitForSingleObject を
使用して排他制御を実施します。この際、MSDN によると戻り値としては
以下のものが定義されています。
WAIT_ABANDONED
WAIT_OBJECT_0
WAIT_TIMEOUT
私の理解では「排他制御に成功した場合」には WAIT_OBJECT_0 が
返るものと思っています。WaitForSingleObject の第2パラメータに
INFINITE を設定した場合、有効なハンドルを与えていれば
「排他制御を実施できるまで復帰しない」と理解しています。
ですが、作成したプログラムが使用するとあるスレッドで、
WaitForSingleObject の戻り値が WAIT_OBJECT_0 でなかったにも
関わらず、他のスレッドが同じ関数を呼び出した際に(排他制御が
実施されているのか)最初のスレッドが排他を解除するまで
WaitForSingleObject で足止めを受けることがありました。
また、WAIT_OBJECT_0 以外が返り排他制御が有効になった際に、
ReleaseMutex により解除してもそのまま排他制御が有効なままと
なっていることがあるように思えます。
排他制御を含む処理を行っている関数にはパラメータで
ミューテクスハンドルを与えていましたが、症状から
メモリ破壊などもあるかと思い、関数内でハンドルをその度に
作成するようにもしてみましたが、結果は同様でした。
質問です。
以下は WaitForSingleObject に有効なハンドルを与えることを
前提としています。
・WaitForSingleObject の戻り値が WAIT_OBJECT_0 以外で
排他制御を実施することはありますか
・WaitForSingleObject に INFINITE を与えて実行した場合、
排他制御が実行されないまま復帰することはありますか
・WaitForSingleObject で排他制御を行った後、同じハンドルを
ReleaseMutex を実行した場合に排他制御を解除できないことは
ありますか
以上、ご教示を頂ければ幸いです。
>WaitForSingleObject の戻り値が WAIT_OBJECT_0 以外で
>排他制御を実施することはありますか
MSDNに書いてますが戻り値がWAIT_ABANDONEDでも排他制御できてます
>WaitForSingleObject に INFINITE を与えて実行した場合、
>排他制御が実行されないまま復帰することはありますか
まちがえてCloseHandleでもしないとないかなと、、
>WaitForSingleObject で排他制御を行った後、同じハンドルを
>ReleaseMutex を実行した場合に排他制御を解除できないことは
>ありますか
基本的にReleaseMutexで解除できます
いちようエラー戻り値WAIT_FAILEDもあるのでGetLastErrorで調べてみるのも手かと。
いまいち問題解決には至らないかもしれませんが、
排他中にCloseHandleや開放忘れ、排他中のスレッドの破棄、親オブジェクトの破棄など
デッドロックしているのか、排他が効いていないのか、どっちかわからん。
デッドロックしているのであれば
本来 MsgWaitForMultipleObjects を使わなければならない状況なのに
誤って/認識不足から WaitForSingleObject を使ってしまっている、とか
排他が効いていない、つーのはあまり経験がないな。
メモリぶっ壊しているとかならありだけど。
WaitForSingleObjectにタイムアウトを設定して、
戻り値がWAIT_TIMEOUTになったらフラグを立てる。
主スレッドでフラグをチェックして
必要があれば何かしらの処理を行う。
ではどうですか?
また、タイムアウトになる時を調べて、デッドロックになってないか
調べるのもありかと思います。
どうしても言葉が気になる。
WaitForSingleObjectを実行しただけで排他制御の実施とか復帰とか。
WaitForSingleObjectでミューテックスの所有権を獲得してから
ReleaseMutexで所有権を解放するまでが排他制御だから。
俺的には所有権とかシグナルとかのほうがしっくりする。
Windowsのミューテックスはカウンタがありプロセス間にも使える。
同じスレッドが同じミューテックスを二度獲得できる。
void func2() {
WaitForSingleObject略
ReleaseMutex略
}
void func1() {
WaitForSingleObject略
func2();
ReleaseMutex略
}
という使い方ができるようになっている。(Windowsの場合)
同じミューテックスを二度獲得したらReleaseMutexは二度呼ぶことになる。
ミューテックスを獲得したままプロセスが死んだら
自動でReleaseMutexしてくれてWAIT_ABANDONEDが返されるらしいね。
WAIT_ABANDONEDは経験ない。
あと別のスレッドで獲得したものを解放はできない。
獲得したスレッドで獲得した回数分解放する。
紅'です。
皆さま、返信をありがとうございます。
遅くなってしまってすみません。
その後、いただいたアドバイスをもとに調べてみましたが、あまり進展がありません。
以下のことをログを仕込んで確認してみました。
・同じミューテクスハンドルを使用している別の関数では同じ現象は起きていない
・WaitForSingleObject() の戻り値を調べたら 0x50 が返ることがあった
・上のほかは WAIT_TIMEOUT か WAIT_OBJECT_0 だった
・GetLastError() を調べたらいつも 0 だった
・ReleaseMutex() はちゃんと通るパスにあって、これを忘れた為にデッドロックに
なっているわけではない(設定/解除が対で実行されていた)
・問題の処理をしている関数にパラメータでミューテクスハンドルを渡すと、
成功する場合と失敗する場合とがあるが、関数内でハンドルを作成すると
WaitForSingleObject() で必ず失敗する?
WaitForSingleObject() そのものよりも別なところがあやしいですね。。。
調査を続けますが、使い方などの原因がわかったら、また報告させていただきます。
結論が出るかわからないので、今の時点で「解決」のチェックを入れておきます。
>どうしても言葉が気になる。
やはり気にされる方もいらっしゃいますね。
自分も用語的には気にならないこともないのですが、ほかの人と話すときに
言葉としてわかりやすいので使っていました。相手によって気をつけるようにします。
以上です。