Home
Blog
Company
TechMemo
Contact
メニュー
スタッフブログ
会社案内
技術系備忘録
お問い合わせ
旧ホームページ
ブログ更新履歴
2024/03/11
rlib-MML 機能追加しました
2023/12/16
rlib-MML アプリ ver1.0.6 公開しました
2023/11/13
rlib-MML 機能追加しました
2023/01/06
rlib-MML アプリ ver1.0.5 公開しました
2021/12/01
rlib-MML アプリ 更新しました
コンテンツ更新履歴
最新の30件
2024-04-13
技術系備忘録/Docker/Emscripten
2022-10-24
技術系備忘録/Windows/接続されているモニタ以上の解像度でデスクトップ表示
2021-10-14
技術系備忘録/C++/小技/無名関数の再帰をローテクで
2021-08-10
技術系備忘録/C++/小技
2021-08-08
技術系備忘録/C++/小技/型で条件分岐
2021-06-10
技術系備忘録/Docker/サーバー死活監視スクリプト
2021-03-29
技術系備忘録/C++/Boost/boost.formatを使った文字列フォーマット。printf系関数を置き換え
2020-10-21
技術系備忘録/VMware/Ubuntu8.10にVMwareServer1.0をインストール
2020-10-14
技術系備忘録/VMware
技術系備忘録/VMware/CentOS7にVMwarePlayer12をインストール
2020-06-03
技術系備忘録/TypeScript/二分探索(binary search)
2020-06-01
技術系備忘録/Docker/SSLアクセラレータ&リバースプロキシ
2019-11-08
技術系備忘録/C++/OpenSSL/ビルド方法
2019-11-04
技術系備忘録/C++/VisualStudio/MSBuild.exeのパスを解決して実行
2019-10-02
MenuBar
2019-09-05
技術系備忘録/Docker
2019-09-04
技術系備忘録/Docker/LAMP環境構築
2019-07-16
会社案内/品質管理方針
2019-04-18
技術系備忘録/AWS/SoftEtherを使ってVPN接続
2019-02-18
技術系備忘録/C++/小技/std.set map系の比較関数の新機能
2018-05-25
技術系備忘録/データベース
技術系備忘録/データベース/SQLite
技術系備忘録/データベース/SQLite/WHERE IN で複数指定するクエリ
2018-05-20
会社案内/求人情報
2018-01-11
技術系備忘録/AWS/EC2 AmazonLinuxにSWAPを設定
技術系備忘録/AWS
2017-11-21
技術系備忘録/C++/Boost/インストール手順
2017-10-25
技術系備忘録/C++/Boost
技術系備忘録/C++/VisualStudio
技術系備忘録/C++/Boost/boost.asioコルーチン内で表コンテキストの処理を行う
リンク
rlib-MML デモページ
MML (Music Macro Language) をコンパイルし、再生や標準MIDIファイル出力をブラウザ上で行える形にまとめています。
Magome
クラウドベースのMIDIシーケンサ
音楽制作に興味のある方を対象に、スタンドアロンでも使え、ネットならではの面白さも兼ね備えた音楽制作アプリの提供を目指しています。
twitter
Tweets by thinkridge
(有)シンクリッジは 技術者 を募集しております。
|
一覧
検索
最新
ヘルプ
ページへ戻る
履歴
印刷
技術系備忘録/C++/最適化小手先テクニック/経過時間の判断方法の穴に落ちるべからず
のソース
xpwiki
:
技術系備忘録
/
C++
/
最適化小手先テクニック
/
経過時間の判断方法の穴に落ちるべからず
のソース
差分
を表示
技術系備忘録/C++/最適化小手先テクニック/経過時間の判断方法の穴に落ちるべからず
へ行く。
コード最適化とは違うネタです。すみません。さて。 "n秒間リトライを繰り返してみる。n秒過ぎたら諦めて抜ける" というチュエーションは良くあると思います。 これを実現する為に書いたコードはリスト1です。 (わかりやすい例にするために、60秒間繰り返すというシンプルなコードにしてみました。) -List1 #prettify{{ DWORD nEnd = ::GetTickCount() + 60000; // 処理開始から60秒後のシステムカウンタを求める while(true){ Retry(); // ←適当な処理 DWORD n = ::GetTickCount(); // 現在のシステムカウンタを取得して、 if( n >= nEnd ) break; // 60秒以上経過してたら抜ける } }} このリスト1にはミスが潜んでいることは気づくでしょうか? このコードは、一見正しく動きますが、ものスゴイ低い確率で無限ループに陥るケースが隠されています。 WindowsAPI の GetTickCount は、システム起動からのカウンタ(経過時間)をms単位で取得します。 GetTickCount から取得される経過時間は、DWORD(符号なし32Bit)ですので、値は 0~0xFFFFFFFF までです。 ということは、Windowsの起動から 0xFFFFFFFF(約50日後) 経過後には、オーバーフロウしてカウンタは 0 に戻ります。 リスト1に話を戻します。 もし仮に、最初の ::GetTickCount() の戻り値が 0xFFFF0000 だった場合、 変数 nEnd には、0xFFFFEA60 (= 0xFFFF0000 + 60000 ) という値が入ります。 すると、どういうことかというと、 whileを抜けれる条件は、::GetTickCount()の戻り値が、 0xFFFFEA60 ~ 0xFFFFFFFF の間、つまり約5秒間しかありません。 その5秒を逃してシステムカウンタが0に戻ってしまった場合は、whileを抜けることが出来ません。 (厳密には50日後に抜けれる機会がまたやってきます) というわけで、このようなミスに陥らない為には、リスト2のようにします。 -List2 #prettify{{ DWORD nBegin = ::GetTickCount(); // 処理開始のシステムカウンタを保持 while(true){ Retry(); // ←適当な処理 DWORD n = ::GetTickCount() - nBegin; // 処理開始から現在までの経過時間を求める if( n >= 60000 ) break; // 60秒以上経過してたら抜ける } }} 大事なのは、 DWORD n = ::GetTickCount() - nBegin; // 処理開始から現在までの経過時間を求める の部分です。 現在時間 - 開始時間 という引き算をすることで、純粋な経過時間が取得出来ます。 こうすることで、もし仮の while の最中に、システムカウンタのオーバーフロウ(カウンタが0に戻る)しても、 正しい経過時間で判断することが出来ます。 まとめ。 説明しやすかったので、WindowsのAPIを使った例になりましたが、Windows以外でも理屈は同じです。特に組み込みソフトなどでは同じようなシチュエーションがあるのではないでしょうか。 この手の問題で一番厄介なのは、一見正しく動いてしまうことです。 しかも無限ループに陥る確立が極端に低い為、原因究明は困難です。 日ごろから色々なケースを想定したコーディングを心がける必要がありそうです。
技術系備忘録/C++/最適化小手先テクニック/経過時間の判断方法の穴に落ちるべからず のバックアップソース(No. All)
現: 2016-03-31 (木) 17:00:32
takatsuka
ぺージ情報
ぺージ名 :
技術系備忘録/C++/最適化小手先テクニック/経過時間の判断方法の穴に落ちるべからず
ページ別名 :
未設定
ページ作成 :
takatsuka
閲覧可
グループ :
すべての訪問者
ユーザー :
すべての訪問者
編集可
グループ :
なし
ユーザー :
なし
Counter: 1782, today: 1, yesterday: 2