きちんと検証したこと無かったのですが、今までの経験から避けていた
別スレッドでのウィンドウ作成
は CreateWindow() の仕様上、対応していなかったみたい。
これだけだと語弊があるので言い直しますが、
GetMessage() / DispatchMessage() / TransalteMessage()
を実装していないスレッド上で、CreateWindow() を行っても、メッセージループ処理
が行われない為、フリーズするということです。
メインスレッド以外でウィンドウを作成する場合は、そのスレッドでもメッセージループ
を実装してやらないとダメ。
昔、DirectX の初期化を別スレッドでやろうとして、一部どうしてもうまくいかない時が
あったのですが、それもこれ関連かも。
DestroyWindow() がメインスレッド以外では無効というのは昔から知っていたのですが、
それもメッセージループのと関係していたってことか。
あと非常にハマりやすいのが、
SetDlgItemText() や SetDlgItemInt() や SetWindowPos()
などは全部 SendMessage() で行われる為、別スレッドにてロックオブジェクトを使い
ロックした状態で Setxx() を呼ぶコードがある場合は、
メインスレッドでロックオブジェクトを使ってるシーン(関数)に入ろうとするとフリーズ…
というよりデッドロックが、起こりえます。
ウィンドウメッセージは、あくまでメインスレッド(CreateWindowをしたスレッド)から
呼び出されるという点が重要ですね。
デッドロックするシーンがあるか紙に書いてみると、当たり前のようにあった。
そもそも Set XXXX 系の関数をロックオブジェクトをロックしたまま呼び出すコードは、
危険な可能性は秘めていると痛感しています。
デッドロックするわけないだろと思ってたのですが、SendMessage() を利用している関数
という意識が外れると、中々気づかないものですね。
0 コメント:
コメントを投稿