Windows2003Server、VisualStudio2003.NET
で、SDKのウィンドウズアプリなのですが
ウィンドウプロシージャの中でSleepをしながら
ある処理を30回ぐらい行っているのですが
その間に、違うプロセスからPostMessageで
メッセージを受けて取っています。
現状、このSleepをしながら
実行している処理が全て終わると、
受け取っていたメッセージを処理しています。
ウィンドウプロシージャの中でSleep
してい、他のメッセージは待ちになった
と認識しています。
が、しかし、他のPC(Windows2000)では
全て終わるまでに、メッセージを受信しています。
このWindows2003でも、このSleppの秒数を
少し変えると、少し受信したりします。
私の認識と違う動きをしているのですが
メッセージループ中のSlepp中にも、別のメッセージの処理は可能
なのでしょうか。
また、OSやコンパイラ、あるいはオプションによって
この動きが変わったりするでしょうか。
Sleep()は、それを実行したスレッドに対して効果を発揮します。
実際のところSleep()を実行したスレッドがメッセージポンプに相当する
ルーチンを含む場合は、たしかにそのメッセージポンプは停止します。
従って「そのメッセージポンプで供給されるメッセージは停止」します。
ですが、ウインドウプロシージャは、当該のアプリケーションのメインスレッド
からだけでなく、その他の任意のスレッドや、OSのカーネルから任意の
タイミングで実行される可能性があります。場合によってはメッセージキューを
経由しないので、メッセージキューを止めていても実行できてしまいます。
結論としてSleep()はメッセージを滞留させる目的には使用できない。ことになります。
ちなみに、ウインドウプロシージャが割り当てられた有効なHWNDの全てに対して
実行できることを考えれば、できるだけ速やかにreturnするべきなのはあたりまえです
ね。
つまり、ウインドウプロシージャは任意のタイミングで受領する全てのメッセージ
に対して速やかに、また正常に動き続けることをOSのポリシーとして要求されている
わけです。
従って、たとえばウインドウプロシージャ内の、メッセージで分岐する前後にSleep()を
するのは、最悪のコードと言えるでしょう。
僕も、仲澤さんの意見と同じですね。
確か、そのソフトの処理に比例しますが、ウインドウメッセージをみる時間は
通常200mS以上と一定だと思いました(違ってたらフォロー願います。)
そこにSleep()を入れるとウインドウのシステムで予定していた処理のタイミングが
ずれることになりますね。
となると埋め合わせはそのソフトのメッセージ処理の間隔をずらすことに
なると思います。
回答ありがとうございます。
必ずメッセージ停止するわけではないのですね。
>その他の任意のスレッドや、OSのカーネルから任意の
は、確かに動きそうです。
しかし、質問した内容に誤りがありました。
外部プロセスからのPostMessageで動作する処理が
動いていないのではなく、自身のプロセスの処理が描画されていませんでした。
以下のような状況です。
メッセージループ {
処理
自身の持つTextBoxに処理したことを表示 ★
Sleep(3000)
}
この★の処理が場合によって、描画されたりしなかったりします。
描画される方は、Windows2000で、描画されない方はWindows2003 Serverです。
(Windows2003のサーバーの方がスペックは高速)
どんな原因が考えられるでしょうか。
http://msdn.microsoft.com/en-us/library/ms644927(v=vs.85).aspx
About Messages and Message Queues
ここを見ると、ghost windowができるようです。
(xpの仕様のようですが、Windows2003 Serverはわかりません。)
メッセージループ {
処理
自身の持つTextBoxに処理したことを表示 ★
Sleep(3000) ☆
}
★の反映が☆で止められている、というだけでは?
WM_PAINTや WM_ERASEBKGNDなどなど描画を行うための
メッセージが止まるので描画されないのでしょう。
どちらにしろ仲澤さんのおっしゃる通り。
タイマーか何かで制御した方がよいです。
すいません。ソースを修正して良い立場でかかわっておらず
なぜ、Windows2000だとOKで、Windows2003だと駄目なのかを
明確にしたい状況です。
なかなか、難しい問題だってのはわかってきましたが。
作り的には、こんな作りは絶対にやらないですね。
> なぜ、Windows2000だとOKで、Windows2003だと駄目なのかを
> 明確にしたい状況です。
以下、机上で論じてみた話。
> メッセージループ {
> 処理
> 自身の持つTextBoxに処理したことを表示 ★
> Sleep(3000)
> }
まず、WM_PAINT メッセージはメッセージキューにメッセージが無い時のみウィンドウプ
ロシージャに渡される。つまり、
> 自身の持つTextBoxに処理したことを表示 ★
> Sleep(3000)
を処理して「メッセージループ(GetMessage() とか)」の処理に戻った時にメッセージ
キューが空で無いと描画(WM_PAINT)処理は行われない。
> その間に、違うプロセスからPostMessageでメッセージを受けて取っています。
PostMessage をどの程度の間隔で投げてるのかは知らないが”Sleep(3000)”としている以
上、3秒以下の間隔でPostMessageされていると、理論上処理を終えるまでメッセージ
キューが空になる事は無い。
> 描画される方は、Windows2000で、描画されない方はWindows2003 Serverです。
> (Windows2003のサーバーの方がスペックは高速)
Windows2000はヘボイので処理が遅くPostMessageする間隔が3秒より多く掛かっている。
そのため処理中にメッセージキューが空になるタイミングがある。
2003 Serverは高specなので処理が速くPostMessageする間隔が3秒未満で済んでいる。そ
のためSleepを抜ける前に新たなメッセージが届き、処理終了までメッセージキューで待
ちが発生している。
という事が起こっていて差がでている可能性もある…かも。
> 動いていないのではなく、自身のプロセスの処理が描画されていませんでした。
UpdateWindow() を入れてやれば描画されるようになるかもしれない。
>しかし、質問した内容に誤りがありました。
仕切りなおしをしていますが、
最初に書いた「違うプロセスからPostMessage」などといった条件は
完全に無視して考えてよろしいのでしょうか?
新規質問しなおすまでは必要ないと思いますが
仕切りなおす場合、それ以前に書かれたことをどう扱うのか、説明お願いします
> 処理
> 自身の持つTextBoxに処理したことを表示 ★
> Sleep(3000)
ここでいうTextBoxとプロシージャに結び付けてあるウィンドウの関係や
「表示処理」って具体的にどんなでしょうか?
#SetWindowTextだけとか、さらに再描画を促すようにしてあるか?とか・・・
もし、
「仕事上、信用おけるソースによる明確な違いの提示」が必要となると
マイクロソフトにきちんと聞いたほうがいいのではないかと思います
うーーん、
まず
何のために3秒待たなければいけないのか?
がわからないです。
・おかしいのはわかっているのだが、顧客に渡ってしまっている。
・関連の事項のクレームが出てしまっている。
・あまり手を加えないで素早く修正したい。
ってことですか?
2003はサーバOSなので、ビデオの描画能力も低く、そのせいのでは?
ここあたりは詳しくないですが。