環境 Windows XP、VC++ MFC
メインスレッドからワーカースレッドへ
メッセージを通知したいので、
PostMessage を使用しようかと思っています。
ただ、PostMessage は、PeekMessage、GetMessage などで、
受信できない場合がある(取りこぼし?)と聞いた事があるのですが
本当にあるのでしょうか?
PostMessage の戻り値が 0 以外ならば、
ワーカースレッド側で必ず取得できるのでしょうか?
以上、よろしくお願いします。
ワーカースレッドからメインスレッド(UI)へメッセージを送ることは
有るけど、逆はやったことがない。本当にそんなことが必要なの?
メッセージを受けるってことはメッセージループが必要になるけど、
ワーカースレッドにメッセージループを書く気なの?
考え直した方がいいと思う。
maruさん、ありがとうございます。
ワーカースレッドでは、
RS232Cで接続されているハードウェアと随時通信をしています。
そこに、メインスレッド(UI)から、命令をしたい場合があるのです。
現状 常に、メインスレッドと、ワーカースレッドがあるんですが
そんな事をしてはいけないのでしょうか?
それとも、メッセージループは、あまりよろしくないって事でしょうか?
> それとも、メッセージループは、あまりよろしくないって事でしょうか?
そもそもワーカースレッドにはメッセージキューがないのにどうやって
メッセージを取り出すつもり?
普通はワーカスレッドで実行する為のデータを準備してスレッドファンクションにそのポインタを渡すものだけど。
スレッド実行中にそのデータを変えたい場合でも、そのポインタ経由で実行すればよい。ただし、データの同期には気をつける必要がある。
>そもそもワーカースレッドにはメッセージキューがないのにどうやって
>メッセージを取り出すつもり?
あれ!?
本当だ。。。
すみません、勘違いしてました。
メッセージキューはあると思ってました。。。
>普通はワーカスレッドで実行する為のデータを準備してスレッドファンクションにそのポインタを渡すものだけど。
>スレッド実行中にそのデータを変えたい場合でも、そのポインタ経由で実行すればよい。ただし、データの同期には気をつける必要がある。
これは、すでにやっているので大丈夫です。
ちなみに、ワーカースレッドからメインスレッドへのPostMessageだと
戻り値が0以外ならば大丈夫なのでしょうか?
> ちなみに、ワーカースレッドからメインスレッドへのPostMessageだと
> 戻り値が0以外ならば大丈夫なのでしょうか?
何をそんなに心配しているんだかわからないけど、PostMessageは対象の
メッセージキューにメッセージを追加できたところで0以外を返すと思わ
れるが、そのメッセージが取り出されるかはわからない。
極端な例だが、PostMessageを実行した直後にUIスレッドが終了してしま
ったら、そのメッセージは取り出されないだろう。もしかするとQUITメッ
セージは最後に取り出されるようにWindowsによって調整されているかも
しれないが...
普通は、ワーカスレッドからメッセージが来る可能性があるのであれば、
ワーカスレッドが終了するまで、UIスレッドは終了しないように作って
おく。
なお、
> ただ、PostMessage は、PeekMessage、GetMessage などで、
> 受信できない場合がある(取りこぼし?)と聞いた事があるのですが
> 本当にあるのでしょうか?
という話は私は聞いたことがありませんし、体験したことは有りません。
> そもそもワーカースレッドにはメッセージキューがないのにどうやって
> メッセージを取り出すつもり?
というのはどうなんですかね。
ワーカースレッドでもメッセージキューを作ってメッセージループを回すことはできます。
もっとも、GetMessage したらスレッドがロックしてしまうので、PeekMessage を使うことになるでしょうけど。
で、用語の定義として、メッセージキューを持ったスレッドはワーカースレッドと呼ばずに UI スレッドと呼ぶ、というのはまぁ、アリだと思います。
ウィンドウを一つも所持していないのに UI スレッドというのも違和感がありますが。
その場合は UI スレッドをワーカー的用途に使うだけです。
個人的にはメッセージキューを持っていようがいまいが、ワーカー的用途のスレッドならワーカースレッドと呼びたいですけど。
> メッセージキューはあると思ってました
一応、ワーカースレッドにメッセージキューを作る事はできる。
PeekMessage(&msg, NULL, WM_USER, WM_USER, PM_NOREMOVE);
とスレッド関数の頭で行い、メッセージループを廻してやれば良い。詳しくは↓
http://msdn.microsoft.com/ja-jp/library/cc410979.aspx
まぁ、コレを「ワーカースレッド」と呼称するのかは疑問だが。(「ユーザインターフェイススレッド」だな)
MFCならば、CWinThread というクラスでユーザインターフェイススレッドを簡単に扱える。
> 受信できない場合がある(取りこぼし?)と聞いた事があるのですが
先に紹介したMSDNページ内にある「PostThreadMessage 関数を使って送信したメッセージは…」という部分を勘違いして記憶していた、って事は無いだろうか?
16ビットOS時代にはメッセージキューの溜め込める数があまり多くなくて
受信側の処理は遅く、送信は頻繁
だったときにパンクしてしまうことがある
と聞いたことがある
32ビット以上になってからは聞かないな
> 受信できない場合がある(取りこぼし?)と聞いた事があるのですが
原理的にはありえますが、現実的にはないと思ってよいです。
メッセージは種類によってその優先度が異なります。
メッセージキューはFIFOほど単純ではないので、優先度の高い
メッセージが高頻度でたまり続けると、いつまでたっても
送信されずにキューに残り続けるメッセージがありえます。
また、キュー内の同じメッセージが一つにまとめられることも
あります(WM_PAINT等)。この場合は発生したメッセージ数と
受信できるメッセージ数が異なるという現象になるわけです。
皆様、貴重な情報ありがとうございます。
> 受信できない場合がある(取りこぼし?)と聞いた事があるのですが
どこから聞いたのか忘れてしまいましたが
通知しているのに、動かないって事があったら嫌だな
と思ったので。
ありえないとの事で安心しました。
ありがとうございました。
デフォルトでは各メッセージキューの最大値は10000。
(PostMessage 10000で検索よろし)
PostMessageの受け側が同メッセージの重複を取り除くか、
送り側が未処理メッセージの有無を確認するか、
あるいは別の何かが必要になるかもしれません。