ページへ戻る
印刷
技術系備忘録/C++/最適化小手先テクニック/経過時間の判断方法の穴に落ちるべからず
をテンプレートにして作成 ::
シンクリッジ
xpwiki
:技術系備忘録/C++/最適化小手先テクニック/経過時間の判断方法の穴に落ちるべからず をテンプレートにして作成
開始行:
コード最適化とは違うネタです。すみません。さて。
"n秒間リトライを繰り返してみる。n秒過ぎたら諦めて抜ける"
というチュエーションは良くあると思います。
これを実現する為に書いたコードはリスト1です。
(わかりやすい例にするために、60秒間繰り返すというシン...
-List1
#prettify{{
DWORD nEnd = ::GetTickCount() + 60000; // 処理開始から6...
while(true){
Retry(); // ←適当な処理
DWORD n = ::GetTickCount(); // 現在のシステムカウンタ...
if( n >= nEnd ) break; // 60秒以上経過してたら抜ける
}
}}
このリスト1にはミスが潜んでいることは気づくでしょうか?
このコードは、一見正しく動きますが、ものスゴイ低い確率で...
WindowsAPI の GetTickCount は、システム起動からのカウンタ...
GetTickCount から取得される経過時間は、DWORD(符号なし32Bi...
ということは、Windowsの起動から 0xFFFFFFFF(約50日後) 経過...
リスト1に話を戻します。
もし仮に、最初の ::GetTickCount() の戻り値が 0xFFFF0000 ...
変数 nEnd には、0xFFFFEA60 (= 0xFFFF0000 + 60000 ) とい...
すると、どういうことかというと、
whileを抜けれる条件は、::GetTickCount()の戻り値が、
0xFFFFEA60 ~ 0xFFFFFFFF の間、つまり約5秒間しかありませ...
その5秒を逃してシステムカウンタが0に戻ってしまった場合...
(厳密には50日後に抜けれる機会がまたやってきます)
というわけで、このようなミスに陥らない為には、リスト2の...
-List2
#prettify{{
DWORD nBegin = ::GetTickCount(); // 処理開始のシステム...
while(true){
Retry(); // ←適当な処理
DWORD n = ::GetTickCount() - nBegin; // 処理開始から現在...
if( n >= 60000 ) break; // 60秒以上経過してたら抜...
}
}}
大事なのは、
DWORD n = ::GetTickCount() - nBegin; // 処理開始から現在...
の部分です。
現在時間 - 開始時間 という引き算をすることで、純粋な経過...
こうすることで、もし仮の while の最中に、システムカウンタ...
正しい経過時間で判断することが出来ます。
まとめ。
説明しやすかったので、WindowsのAPIを使った例になりました...
この手の問題で一番厄介なのは、一見正しく動いてしまうこと...
しかも無限ループに陥る確立が極端に低い為、原因究明は困難...
日ごろから色々なケースを想定したコーディングを心がける必...
終了行:
コード最適化とは違うネタです。すみません。さて。
"n秒間リトライを繰り返してみる。n秒過ぎたら諦めて抜ける"
というチュエーションは良くあると思います。
これを実現する為に書いたコードはリスト1です。
(わかりやすい例にするために、60秒間繰り返すというシン...
-List1
#prettify{{
DWORD nEnd = ::GetTickCount() + 60000; // 処理開始から6...
while(true){
Retry(); // ←適当な処理
DWORD n = ::GetTickCount(); // 現在のシステムカウンタ...
if( n >= nEnd ) break; // 60秒以上経過してたら抜ける
}
}}
このリスト1にはミスが潜んでいることは気づくでしょうか?
このコードは、一見正しく動きますが、ものスゴイ低い確率で...
WindowsAPI の GetTickCount は、システム起動からのカウンタ...
GetTickCount から取得される経過時間は、DWORD(符号なし32Bi...
ということは、Windowsの起動から 0xFFFFFFFF(約50日後) 経過...
リスト1に話を戻します。
もし仮に、最初の ::GetTickCount() の戻り値が 0xFFFF0000 ...
変数 nEnd には、0xFFFFEA60 (= 0xFFFF0000 + 60000 ) とい...
すると、どういうことかというと、
whileを抜けれる条件は、::GetTickCount()の戻り値が、
0xFFFFEA60 ~ 0xFFFFFFFF の間、つまり約5秒間しかありませ...
その5秒を逃してシステムカウンタが0に戻ってしまった場合...
(厳密には50日後に抜けれる機会がまたやってきます)
というわけで、このようなミスに陥らない為には、リスト2の...
-List2
#prettify{{
DWORD nBegin = ::GetTickCount(); // 処理開始のシステム...
while(true){
Retry(); // ←適当な処理
DWORD n = ::GetTickCount() - nBegin; // 処理開始から現在...
if( n >= 60000 ) break; // 60秒以上経過してたら抜...
}
}}
大事なのは、
DWORD n = ::GetTickCount() - nBegin; // 処理開始から現在...
の部分です。
現在時間 - 開始時間 という引き算をすることで、純粋な経過...
こうすることで、もし仮の while の最中に、システムカウンタ...
正しい経過時間で判断することが出来ます。
まとめ。
説明しやすかったので、WindowsのAPIを使った例になりました...
この手の問題で一番厄介なのは、一見正しく動いてしまうこと...
しかも無限ループに陥る確立が極端に低い為、原因究明は困難...
日ごろから色々なケースを想定したコーディングを心がける必...
ページ名: