原因は、処理落ち!?
最近のPCは、性能が上がったので処理落ちなどと無縁かと思いきや
どうやら、そんな事は無いようだ。
ちなみにOSによってちょっと動作が異なる場合もある。
随分前にあるゲームのメインループを「SetTimer」で
一定時間で処理をするように作ってみた所、
ある条件で下で動かなくなってしまう不具合が現れた…。
はっきり言ってまるで原因がわからん!
色んなPCで実行してみたりしてみたらどうやら
遅いPCでは発生するが、速いPCでは発生しないらしい…。
もしかして割り込み時間を変えると現象が変わるかとやってみたら変わった。
割り込み設定時間によって動作が怪しくなる…。
タイマー割り込みで描画処理までやってしまうのが悪いのか?
…
…
…
悪いんだろう…。
割り込み中に割り込みが発生すると多重にかかってしまう。
自分のPCでは、タイマー内処理が重くて他のタイマー割り込みが
入れない状態になってたと言うのが結論。
描画処理を削除するときちんとタイマー割り込みが入るようになった。
その後色々やってみて遅いPCでも動作する値を探した…。
対処療法的ですが…。
だからって、本当にタイマー割り込みが原因なのだろうか?
どうしたら確認ができるか?
その後もイジイジやっていったら…
「SetTimer」だけだと処理落ちが発生しても最低一回は割り込みが入る模様。
「SetTimer&KillTimer」だとまた若干動向が変わる。
なんか色々分かったような気がした
…
でも忘れた♪www
…
取り敢えずその時検証をプログラムを作ってみた。
その時に利用した検証用PCのスペック。
CPU=Celeron 1.3GHz/FSB=100MHz/MEMORY=512MB/VDP=GeForce FX5200
OS=Windows2000/Window98
//******************************************************************************
// 「SetTimer」の検証
// 1~9の数字を入力するとタイマー割り込みが作成されます。
// 8は、処理落ちテスト用の番号で「Sleep(1000)」を実行します。
// その後8以外の割り込みが発生しないのを確認できます。
// 同じ番号を押すとタイマー割り込みを解除できます。
// ESCキーでも終了します。
// Zキーで「KillTimer/SetTimer」処理のON/OFFができます。
// 2K系だと処理落ちした時でもOFFなら他のタイマーを必ず1回呼びます。
// 9X系は、関係有りませんでした。
//******************************************************************************
//**************************************
#include <windows.h>
//**************************************
char History[40];
char Count;
UINT TimerList[10];
BOOL KillSetFlag = TRUE;
//**************************************
// 番号が小さい方が早い割り込みになります。
void SetTimer( HWND hWnd, int Index )
{
if( TimerList[Index] == 0 )
{
TimerList[Index] = SetTimer( hWnd, Index, Index * 10, NULL );
} else
{
KillTimer( hWnd, Index );
TimerList[Index] = 0;
}
}
//**************************************
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch( message )
{
case WM_CREATE:
SetTimer( hWnd, 9 );
return DefWindowProc( hWnd, message, wParam, lParam );
case WM_TIMER:
// 「KillTimer/SetTimer」のセットで
// 現在溜まっているキューを削除できます。
// 処理が間に合わない場合、キューにメッセージが溜まります。
// それを削除する手法の一つです。
if( KillSetFlag )
{
KillTimer( hWnd, wParam );
SetTimer( hWnd, wParam, wParam * 10, NULL );
}
// 処理落ちを再現します。
if( wParam == 8 )
Sleep( 1000 );
if( ++Count >= sizeof( History ) - 1 )
{
Count = 0;
ZeroMemory( History, sizeof( History ) );
}
*History = KillSetFlag ? '*' : '-';
*( History + strlen( History ) ) = ( char )( wParam + '0' );
InvalidateRect( hWnd, NULL, TRUE );
break;
case WM_CHAR:
if( wParam == VK_ESCAPE )
{
DestroyWindow( hWnd );
} else if( ( '1' <= wParam ) && ( wParam <= '9' ) )
{
SetTimer( hWnd, wParam - '0' );
} else if( ( wParam == 'z' ) || ( wParam == 'Z' ) )
{
KillSetFlag ^= TRUE;
}
break;
case WM_PAINT:
{
PAINTSTRUCT p;
HDC h;
RECT r;
h = BeginPaint (hWnd, &p);
GetClientRect( hWnd, &r );
DrawText( h, History, strlen( History ), &r, DT_LEFT );
EndPaint( hWnd, &p );
}
break;
case WM_DESTROY:
{
for( int i = 1 ; i < 10 ; i++ )
if( TimerList[i] != 0 )
KillTimer( hWnd, TimerList[i] );
}
PostQuitMessage( 0 );
break;
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
return 0;
}
//**************************************
int APIENTRY WinMain( HINSTANCE hInstance, HINSTANCE, LPSTR, int nCmdShow )
{
LPSTR c = "TimerTest";
MSG m;
WNDCLASSEX w;
HWND h;
ZeroMemory( &w, sizeof( w ) );
w.cbSize = sizeof( w );
w.style = CS_HREDRAW | CS_VREDRAW;
w.lpfnWndProc = WndProc;
w.hInstance = hInstance;
w.hCursor = LoadCursor( NULL, IDC_ARROW );
w.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
w.lpszClassName = c;
RegisterClassEx( &w );
h = CreateWindow( c, c, WS_OVERLAPPEDWINDOW, 100, 100, 400, 100, NULL, NULL, hInstance, NULL );
ShowWindow( h, nCmdShow );
UpdateWindow( h );
while( GetMessage( &m, NULL, 0, 0 ) > 0 )
{
TranslateMessage( &m );
DispatchMessage( &m );
}
return m.wParam;
}
//******************************************************************************
どんなにPCが早くなっても処理の限界はある訳で処理落ちは発生する。
むろん起き難くなるだろうけど、ゲームなどタイミングを要求する処理は
処理時間を考慮しなくてはならなんだろうけど…
ロストプラネットは、CPU1GHzじゃあまともに動きません…。
| 固定リンク
コメント