別に1行1PostMessageでなくてもいいと思うけど。
PstMessageを使うということはどこかにデータをためる機能が必要。
非同期だからいつ使われるか判らないからね。
複数のデータをためとく機能も必要なわけだ。
PstMessageを100回実行しても、
まだ3回目のメッセージ処理を実行していることもあるわけで。
俺ならダイアログの方からタイマーで定期的に
溜まっているデータがあったら反映するようにして
メッセージは使わない。
排他制御必要。
貯める場所はTestDlgのメンバ変数で問題ない。
メッセージのロスが発生しないように処理が重くならないように
適度にメッセージループを回していれば問題ないと思います。
メッセージのロスの方はもしかしたら PostMessage の戻り値でわかるのかも?
ちなみにUI側でスレッドを待機していなければ SendMessage でよくて
スレッド側の操作が終わったら完了通知を PostMessage する作りにしてもよいと思います。
リアルタイムにログデータを採取するようなアプリであればタイマーもありですね。
ツリーコントロールを持つスレッドはTestDlgなのですね。
頻繁にログデータの更新があるのなら、
1. データ更新用のスレッドを作成する。
2. 常時イベント待ちにする。
3. ログデータの更新の都度イベントをONにする。
4. 排他制御として、更新が行なっているときはツリーコントロールで
データを読込まない。(たぶんフラグですむと思う。)
5. データ更新用のスレッドを終了させる。
#忘れやすいです。特に、WaitForSingleObjectのパラメータが
INFINITEになっているときですね。
データ更新用のスレッドは、ツリーコントロールのあるTestDlgで作成する
ようにすればいいと思います。
適当な回答が目立ちますね。
SendMessageでデッドロックとか、あまり鵜呑みにしないように。
メッセージ処理が理解できていない証拠です。
本題ですが、thisを渡してワーカースレッド側から追加ください。
ワーカースレッドの処理が完了する前にツリーアイテムの削除等
操作ができるGUI設計であれば、ツリーアイテムを弄る処理に
排他制御が必要です。
>例えば、極端なケースで1回のUI処理で数千から数万回、PostMessage()を呼ぶというこ
>とは、
>通常、プログラム的にはよろしいのでしょうか?
メッセージの話から離れるのですが
UIに対し、どのくらいの短い期間で数千から数万回の処理をするのでしょうか?
ツリーコントロールに対し、たとえば1秒間に数千・数万も処理をさせる
ってなると、それ自体に問題がおきるような気がします
#そんだけ表示更新しても人間にはそんな変化は知覚できない
また、ダイアログにのせるコントロールは、
あくまでユーザーに見せる表示部分に使うもので
「数千・数万のデータを保持するためのバッファ」として
扱うのはやめたほうがいいです
大量のデータはグローバルなり、ドキュメントクラスなりに領域確保して保存し
ユーザーに見せる分だけを、ダイアログに更新させたほうが安全です。
#見せられるようになったときだけメッセージを送る
> 適当な回答が目立ちますね。
あーごめん。今の今まで SendMessage の動作を誤認していた。
http://msdn.microsoft.com/ja-jp/library/cc411022.aspx
> 他のスレッドが作成したものであった場合、システムはそのスレッドへの切り替えを行
> い、次に適切なウィンドウプロシージャを呼び出します。
スレッドの切り替えを行ってくれてたのね。つー事は SendMessage した場合はスレッド
セーフで他スレッドから投げても問題無いって事なのか。
昔他スレッドからの UpdateWindow でデッドロックした事があり、その流れで
SendMessage も似たようなモノでnotスレッドセーフだと思い込んでいたのかも知れない。
シンヤさんをはじめ他の回答者の方々、誤った情報を出してしまい申し訳無いです。
ZCHさん訂正情報ありがとうございます。助かりました。
> メッセージのロスの方はもしかしたら PostMessage の戻り値でわかるのかも?
わかりますね。実際全力でポストとかすると失敗しますし。
# ryoさん(2009/07/29(水) 00:27:32)の発言とほぼ同感です。
中止などで確実にワーカースレッドが消滅するのを確認するために
プライマリからワーカースレッドが終了するのを待つ処理を書いていて
ワーカースレッドがプライマリのウィンドウにSendMessage、SetWindowText、
その他ウィンドウ操作を行うと
タイミングがあってしまい並列に実行されてしまったときデッドロックする。
最初そういうつもりなかったけど
うっかり書いてしまったことがある。
つ「SendMessageTimeout」
# いや、本質的な解決を目指すべきなんじゃ…。
適当な回答と言われると自信がなくなってきますが
デッドロックが起こる原因は、
1.UIスレッドでワーカースレッドを待機
→ワーカースレッド完了まで待ち状態
(ウインドウプロシージャーを抜けないのでメッセージループが回らない)
2.ワーカースレッドで SendMessage
→SendMessage なのでメッセージが処理されるまで待ち状態
(メッセージはUIスレッドで処理されるがメッセージループが回っていない
のでメッセージは永遠に処理されない)
とお互いに待ち状態になるからだと考えています。
間違っていたらごめんなさい。
この手の話は毎回の如く出てきて毎回の如く同じ話を書いている気がします。(^^;
私が、スレッド間でウインドウクラス(派生を含む)を受け渡しをしないほうが良い
と言う理由には、OSの製造元であるMicrosoftが公式にやっちゃ駄目と書いているから
という事に尽きます。確かに現状の実装を細かく見て行くと今の実装であれば、
使えるかもしれません。しかし、Microsoftが公式に駄目といっている以上、
動かないような実装に変更したとしても公式には何の問題もないわけです。
使っちゃ駄目と書いていましたよねと言われるだけです。
公式に保障されていない方法を使って実装してしまうと
その実装を使って動作している物も保障できなくなってしまいます。
個人で使うようなものであれば、それでも良いと思うのですが、
実際にお客様に提供するものや業務で使用するものに関しては
保証のない方法を使用するべきではないと言うのが私のスタンスです。
技術的な面に関しては細かくMFCのソースを追って行けば、
今の実装では問題ないと言えるかもしれません。
しかし、Microsoftが公式に使って良いと言う見解を出さない限り、
使うべきでは無いと考えています。
SendMessageに関しては、SendMessageの動きをちゃんと理解して使っていれば、
良いと思うのですけれど、何でもかんでもSendMessageにしていると呼び出しが
入れ子になってしまっていつまで経っても返って来ないというケースはありえると
思いますよ。そういう意味ではデッドロックといっても良いかなと思います。
基本的には呼び出し側が拘束されないPostMessageで組み立てるように考えた方が
良いのではと言うのが私の考えです。
SendMessageでしか実装できないケースにまで使うべきではないとは思っていません。
> つ「SendMessageTimeout」
これ使えばタイムアウトで戻っては来るんでしょうけれど、
なんと言うか、問題は他の所にあるような気がしますね。
> # いや、本質的な解決を目指すべきなんじゃ…。
御意。
きちんと仕組みの所から見直すべきだと思います。
俺はあれを信用せずthis渡す派
これはpostmessage推奨を否定してるわけではないので注意
モーダルダイアログのthisはローカル変数なのにTLSだから使えないとか
別の方法にpostmessageがあるという説明だとハンドル渡しならpostmessage使う必要なくなにやっても問題ないと解釈できるわけで
かえってトラブル起こしそうだから見ないほうがイイ気がしてしまうのだ
PostMessageでウインドウメッセージを投げて処理を
ダイアログクラスにやらせると言う思想はスレッドがどうとかと言うのとは
話が別だと私は考えています。
ダイアログボックス内の処理はダイアログボックス内に閉じ込めてしまって
外部からは必要な情報と指示を与えて解決すると言う考え方はオブジェクト
指向で考える時の基本的な思考法だと思いますし。
ダイアログボックス内の処理をダイアログボックスのクラス自身に任せると
ウインドウ間やスレッド間の結合度が弱くなるので組み替えもやりやすくなります。
新しくダイアログを増やして流れを変えるような事もやりやすいです。
ハンドル渡しで出来る事とマルチスレッドを意識して仕組みを設計する事も
別問題ですから、ごっちゃにして考えるのはよく無いと思いますよ。
何を使ったとしてもマルチスレッドで処理をするなら排他処理に関しては
考慮する必要があると思います。
ウインドウクラスのインスタンスを渡して処理するのであれば、
Microsoftが実装を変えてしまった時にわけの分からない不具合に
悩まされるかもしれない事は頭に入れておくべきかと思います。
それもひっくるめて納得済みなら後は各々の判断になりますね。
あと気になるのが、ウインドウハンドルとMFCのウインドウクラスの
インスタンスの関係をきちんと理解していないのではという所です。
ここのところをきちんと理解していれば、
「ハンドル渡しならpostmessage使う必要なくなにやっても問題ない」
と言う解釈は出てこないと思うんです。
逆に言うとこの辺の関係をちゃんと理解していれば、
問題なく処理できるはずではないかと。
MFCのウインドウクラスのインスタンスはあくまでも実体のウインドウを
ラップしたものに過ぎず、実体では有りません。
この部分が理解できていないといろいろな所で間違ったコードを書いて
しまう原因になると思います。
そういう意味では結構大事な知識なんですけれど、
この部分の知識って割りとおざなりですよねぇ。
うーむ。(--;