The deep inside of Windows 〜 Windowsの深淵
Lesson 4.マルチスレッディング【前編】 '02/01/03 今回も時間が無いので走り書きでゴメンなさい。
マルチスレッディングについて詳しく書き出すとキリが無い。マルチスレッドらしいマルチスレッドの話題は、今回は割愛して、Windowsにおけるマルチスレッドプログラミングの注意点みたいなものを書いていくことにする。
まず、Windowsにおいて、スレッドを生成するのはどうやれば良いか?
おそらく、大半の人は、::CreateThreadを使うと言うだろう。しかし、違うのだ。こいつ、C言語のランタイムを呼び出していると、少し(80バイトほど)メモリリークする。だもんで、_beginthreadを使ったほうが無難なようである。
この_beginthreadを使うときは、process.hをincludeして、そのあと、プロジェクトの設定⇒「C/C++」⇒「コード生成」で、「使用するランタイムライブラリ」は、マルチスレッド用のものを選択しておかないといけない。
次に、マウスカーソルの表示/非表示を切り替えるには?
これまた、大半の人はShowCursorを使うと言うだろう。ところで、この関数は引数として、表示/非表示のフラグしかとらない。しかし、実際にこの関数を使ってみればわかると思うのだが、自分の作成したウィンドゥに入ったときのみ効力を発揮するのだ。つまり、非表示にしたところで、自分の作成したウィンドゥの外に出さえすれば、表示される。つまり、暗黙に、自分の作成したHWNDを指定していることになる。(このへんが、WindowsのAPIがオブジェクト指向ライクに出来ていないと言われる部分なのだが)
どうやって、自分の作成したHWNDを確定させているか、詳しい仕組みは逆アセしたわけでは無いので知らないが、おそらくスレッドIDか、それ相当のもので判定しているものだと思われる。というのも、別のスレッドからShowCursorしても、カーソルの表示/非表示は変化しないからである。つまり、ウィンドゥを作成したスレッドが、責任を持ってShowCursorをしなければならないという事実。
これは、DirectDrawに関しても同じで、DirectDrawオブジェクトを作成したスレッド以外が描画しようとしても失敗することがある。(詳しい条件はずいぶん昔のことなので忘れました^^;)
よって、応答性を高めるために、メインスレッドとワーカースレッド(メッセージ処理スレッド)を分けて、ワーカースレッドはメッセージ処理だけを担うようにしようと思っても、このような事情により、うまくいかなかったりする。結局、メインスレッドがワーカースレッドに描画依頼やら、何やらのメッセージを送ってやることになる。こうなってくるとマルチスレッドにすることの恩恵があるのかどうか少し疑問である。まあ、ここではあまり深入りしない。
次に、DirectDrawによるマルチウィンドゥ描画についてである。
ひとつのDirectDraw(LPDIRECTDRAW)につき、ひとつしかプライマリは作れないので、複数ウィンドゥに描画したければ、複数作ってやる必要がある。ところが複数作ろうと思っても、簡単には作れない。
DirectDrawを使用〜終了のときに必須の::CoInitialize(NULL)〜::CoUninitialize( ) これはいつ行なうと良いかというと、COM呼び出しの前に行なわなければならないとどこかに書いてある。だから、COM使用の参照カウンタを用意して、最初に使うときと、最後、終了させるときに::CoInitialize(NULL)〜::CoUninitialize( )していたりする。でも違う。この初期化は、スレッドごとに必要なのである。つまり、スレッドが違うのであれば、その都度、::CoInitializeしなければならないようだ。よって、ThreadIDから、参照カウンタへのstd::map<DWORD,int>でも用意して実装すると良さそうである。
時間が無いので今回はこのへんで。