17

私はかなりタイトなタイミングを必要とするアプリケーションを作成しています。Stopwatchクラスは完璧なソリューションです。ただし、小さなパネルのPCで実行している場合、ストップウォッチの値が大きく外れていることに気付くことがありました。200ミリ秒ごとにストップウォッチの値を監視するデバッグプリントアウトをいくつか追加しました。

0:00:197
0:00:502
0:00:702
...
0:03:356
0:12:93

0:13:21
0:13:421
..。

どうして3秒から13秒にジャンプするのでしょうか。基になる関数QueryPerformanceCounter()にバグがあることがわかりました(QueryPerformanceCounter()に注意してください)が、ここで何か他のことが起こっているように感じます。

任意の洞察をいただければ幸いです。

アップデート:

これが私のコードのもう少し詳細です:それはかなり簡単です。Stopwatchこれは、起動時に新しいオブジェクトを作成し、を介してそれを開始するWPFアプリケーションですStart()DispatcherTimer次に、次のようにを作成します。

displayTimer = new DispatcherTimer(); 
displayTimer.Tick += display_Tick; 
displayTimer.Interval = DISPLAY_INTERVAL_TIMESPAN; 

ここで、タイムスパンは200ミリ秒です。私のデバッグコードは、ティックStopwatchするたびにオブジェクトの値を出力するだけです。dispatchTimer

Update2:

楽しいマイクロソフトのサポート記事は、パフォーマンスカウンター値が予期せず飛躍する可能性があることです

4

3 に答える 3

17

更新(ログを見た後)

すでに述べたように、StopwatchクラスはQueryPerformanceCounterその下の関数を使用します。備考セクションでMSDNは次のように述べています。

マルチプロセッサコンピュータでは、どのプロセッサが呼び出されるかは問題ではありません。ただし、基本入出力システム(BIOS)またはハードウェアアブストラクションレイヤー(HAL)のバグが原因で、プロセッサーごとに異なる結果が得られる可能性があります。スレッドのプロセッサ親和性を指定するには、SetThreadAffinityMask関数を使用します。

Dispatcherを使用しているQueryPerformanceCounterため、経過時間を照会するたびに同じCPUで実行されるとは限りません。

コマンドを使用して実行可能ファイルを呼び出すなど、プロセスのプロセッサアフィニティを指定することで、MSDNに記載されている問題が問題の原因であるかどうかを確認できますstart。10秒はCPU間の大きな遅れのように思えますが、ドキュメントはその違いがどれほど大きいかについて非常にあいまいです。次のコマンドは、アプリケーションを最初のCPUにバインドします。

> start.exe /AFFINITY 1 program.exe

これで問題が解決する場合は、推奨される回避策、つまりオブジェクトSetThreadAffinityMaskをクエリする前に関数を呼び出す方法を確認することをお勧めしStopwatchます。

あなたのコメントはあなたがWPFを使用していると言いましたDispatcherTimer。そのクラスのドキュメントには次のように記載されています。

タイマーは、時間間隔が発生したときに正確に実行されることは保証されていませんが、時間間隔が発生する前に実行されないことが保証されています。これは、DispatcherTimer操作が他の操作と同様にDispatcherキューに配置されるためです。DispatcherTimer操作が実行されるタイミングは、キュー内の他のジョブとその優先順位によって異なります。

これは、特にディスパッチャが他のタスクでビジー状態の場合、タイマーイベントが遅れて到着する可能性があることを意味します。イベントが早期にトリガーされるのを防ぐ他のものをディスパッチャーキューに配置しましたか?

于 2010-08-03T20:23:29.650 に答える
15

PCハードウェアの正確なタイミングは簡単ではありません。ここにいくつかのリソースがあり、Windowsでのタイミングに関するいくつかの経験を示しています。これは、.NETを含むWindows環境でのカウンターの基本的な実装になります。

使用するシステムコールによっては、10ミリ秒の解像度が得られる場合がある理由を説明し、QueryPerformanceCounterが「バギー」である理由をもう少し明らかにします。ポイントの1つは、省電力モード/可変CPU速度がこれらのタイミングに干渉する可能性があることです。

これに関連する概念は、リアルタイムの物理シミュレーションにおける「タイムステップのロック」です。あなたがそれをグーグルで検索すると、あなたはあなたが抱えている問題を回避する方法についていくつかのアイデアを得るかもしれません。基本的な概念は、固定された時間ステップを持ち、タイミング/更新機能に対して一種のプロデューサー/コンシューマーの実装を行うことです。これが特定のドメインに当てはまるかどうかはわかりませんが、ビデオゲームのベストプラクティスと見なされています。

于 2010-08-03T19:57:50.387 に答える
2

おそらく私はあなたの質問を誤解していますが、時間間隔を測定する必要がありますか、それともそれらの間隔でコードを実行する必要がありますか?コードを実行する必要がある場合は、System.Timers.Timerクラスをチェックしてください。これはスレッドセーフであり、マルチプロセッサで正常に機能するはずです。

于 2010-08-03T21:11:27.643 に答える