FAQ12-1
|
Q. Win3.1用プロセス停止プログラムをWin95でも動作させるには
GetTickCount()を利用して,一定時間待機する処理を作ろうとしています.
そこで,リスト12-1のようなコードを作成しました.このコードは,10秒間,自分のプロセスだけを停止するものです.
このコードを,32ビットアプリケーションとして,Windows95で実行してみるとうまくいきません.Windows3.1時代に,16ビットアプリケーションとして使っていたときは正常に動作していたのですが...
実際に動かないことはないのですが,10秒間停止している間,CPUの使用率が100%になってしまい,他のプロセスの動きが遅くなってしまうのです.
Windows3.1時代は,他のプロセスが遅くなるようなことはありませんでした.どうすればよいのでしょうか.お願いします.
[リスト12-1] :
DWORD dwTime = GetTickCount();
while( GetTickCount() - dwTime < 10000 ) {
MSG msg;
PeekMessage( &msg, NULL, NULL, NULL, PM_NOREMOVE );
}
|
|
|
A. Sleep()とスレッドを利用する
PeekMessage()は必要ない
まず,32ビットアプリケーションでは,PeekMessage()を呼ぶ必要はありません.
メッセージを処理するならば,意味がないとは言えませんが,他のプロセスに制御を明け渡すためだけに呼んでいる場合は,ほとんど意味がありません.リスト12-2のように書いても効果は同じです.
しかし,これではCPUの使用率が100%であることには変わりありません.
そこで,32ビットアプリケーションではSleep()という新しいAPIを使います.
[リスト12-2] :
DWORD dwTime = GetTickCount();
while( GetTickCount() - dwTime < 10000 ) {
MSG msg;
if( PeekMessage( &msg, hwnd, WM_MYMESSAGE,
WM_MYMESSAGE, PM_NOREMOVE ) ) {
break;
}
}
Sleep()
Sleep()とは,現在のプロセス(正確にはスレッド)を指定された時間だけ停止させるAPIです.指定する時間は,ミリ秒単位で,
Sleep( 10000 );
というように使用します.
これを使用すれば,CPUを無駄に使用することなく,待機だけをすることができます.
あるアクションがあるまで待機するには,マルチスレッドを利用する
あるアクション,すなわち何かメッセージが送られてきたり,コールバック関数が呼ばれた場合に,Sleep()を中断することはできないのでしょうか.
残念ながらそれはできません.では,何かメッセージが来るまでSleep()するためには,質問にあったようにPeekMessage()ループを使う方法しかないのでしょうか.
しかし,これではまたCPUの使用率が,100%になってしまい,振り出しに戻ってしまいます.確かにループ中にSleep(100)とかを入れることによって,多少は改善されるかもしれませんが,それでは完璧ではありません.
そんな困ったときには,マルチスレッドを使います(リスト12-3).
リスト12-3では,CreateThread()でWaitingThread()というスレッドを作っています.WaitingThread()はSleep()をするだけのためのスレッドです.
メインのコードは,GetMessage()でメッセージが来るのを待機します.GetMessage()は,PeekMessage()とは違い,メッセージが来るまで制御を戻さないので,いく分か効率がよくなります.
GetMessage()した後,DispatchMessage()していないので,前のサンプルとは少し動作が変わってきますが,そこらへんは臨機応変に対応しましょう.
[リスト12-3] :
#define WM_MYMESSAGE (WM_USER + 0)
void MainFunction( void ) {
HANDLE hThread;
DWORD idThread;
hThread = CreateThread( NULL, 8192,
(LPTHREAD_START_ROUTINE)WaitingThread,
NULL, 0, &idThread );
MSG msg;
while( GetMessage( &msg, NULL, NULL, NULL ) ) {
if( msg.message == WM_MYMESSAGE ) {
break;
}
//TranslateMessage( &msg );
//DispatchMessage( &msg );
}
TerminateThread( hThread, 0 );
CloseHandle( hThread );
}
DWORD WaitingThread( LPVOID ) {
Sleep( 10000 );
PostMessage( hwnd, WM_MYMESSAGE, 0, 0 );
Sleep( INFINITE );
return 0;
}
メッセージというアクションだけでなく,コールバック関数が呼ばれたときや,その他のアクションの場合はPostMessage()に変換すればよいでしょう(リスト12-4).
[リスト12-4] :
void CallBackFunction( void ) {
PostMessage( hwnd, WM_MYMESSAGE, 0, 0 );
}
Back to FAQ main page