2009-09-12 7 views
4

私は数年前にC++(MFC、Visual Studio 6.0)でビルドされたプログラムを持っていて、特定のWindowsマシンでかなりの時間(5年以上)実行されていました。 1ヶ月前にPCが交換され(古いものが死亡した)、その後プログラムのタイミング動作が変更されました。理由を理解する助けが必要です。PCを交換した後のSleep()の精度が低下しますか? (C++)

このプログラムの主な機能は、オンとオフの間の非常に正確な遅延で、オンとオフ信号を外部カードに送信することによってキーストロークに応答することです。例えば、プログラムの流れ:

> wait for keystroke... 
> ! keystroke occurred 
> send ON message 
> wait 150ms 
> send OFF message 

異なるキーストロークは20msのと150msの間に、それらに関連する異なる待機期間を、持っている(非常に決定論的な時間は、特定のキーストロークに応じて)。タイミングは非常に重要です。待機は単純なSleep()を使用して実行されます。古いPCの睡眠の正確さは1-2msのずれであった。私は(外部カード上の)コンピュータの外部のタイミングを測定することができるので、スリープ時間の測定は非常に正確です。このようなON-sleep-OFFサイクルを1年に何千回も実行するこのマシンを考慮に入れると、私が持っている精度データは健全です。

PCを交換したため、タイミングのずれは10ms以上です。

私は以前のPCをインストールしていないので、いくつかの追加ソフトウェアパッケージがインストールされている可能性があります。また、以前のPCがWindows 2000かWindows XPかを覚えていないことを認めても恥ずかしいです。私はそれがXPであったと確信していますが、100%ではありません(そして私は今チェックできません...)。新しいものはWindows XPです。

タイマーに基づいてスリープメカニズムを変更しようとしましたが、精度が向上しませんでした。

この変更について何か説明できますか?以前のPCにインストールされている可能性があるソフトウェアパッケージがありますか?問題に対処するベストプラクティスはありますか?

答えて

3

XPでの時間分解能は約10msです。システムは基本的に10msごとに「ティック」します。睡眠は、その理由から正確なタイミングをとるための非常に良い方法ではありません。私はかなりwin2000が同じ解像度を持っていると確信していますが、もし私が間違っていれば、理由があるかもしれません。このhttp://www.lucashale.com/timerresolution/http://technet.microsoft.com/en-us/sysinternals/bb897569.aspxを参照するか、または使用 - -

あなたは1ミリ秒に少なくともダウン、その解像度を変更することができ、レジストリキーが同様におそらくあります(Windowsメディアプレーヤーが変化するという、タイマーをだけでなく、それが実行しているおそらく唯一ながら

+0

Lucas Haleのソフトウェアをダウンロードし、それは明日のセットアップで。私は更新します、ありがとう。 –

+0

関数の名前をsleepish()に変更する必要があります。実際にどれくらいの時間スリープ状態になるのかはいつも分かっています...あなたの以前の設定があなたに正確な結果を与えたことに驚いています! – Kieveli

+0

これについてのドキュメントは明確です。なぜあなたが驚いているのか分かりません。 –

0

スリープはシステムクロックによって異なります。あなたの新しいマシンはおそらく以前のマシンとは異なるタイミングを持っています。 documentationから: がそのタイムスライスの残りの部分を放棄し、 dwMillisecondsの値に基づいて 間隔のunrunnableなるように

この関数は、スレッドを引き起こします。システムクロック は一定のレートで「チック」します。 dwMillisecondsがシステムクロックの 解像度未満の場合、 スレッドは、指定された長さの 未満でスリープすることがあります。 dwMillisecondsが ダミーで2より小さい場合は、 は1と2ティックの間であれば のようになります。 の精度にスリープ期間を増加させるために、呼び出し timeGetDevCapsは にサポートされる最小タイマ分解能 とtimeBeginPeriod関数を決定するように機能し、その 最小にタイマーの解像度を設定します。 timeBeginPeriodを呼び出すときは、頻繁に呼び出すと がシステムクロックに大きく影響し、 システムの電力使用量、およびスケジューラには注意が必要です。 timeBeginPeriodを呼び出す場合は、アプリケーションで早めに と呼び、 関数を アプリケーションの最後に必ず呼び出してください。

ドキュメントは、あなたがそれをより正確にしようとすることを示唆しているようですが、もし私があなただったらそれを試しません。ちょうどタイマーを使用してください。

どのタイマーを交換しましたか? SetTimer()を使用した場合、そのタイマーも吸う。
正しい解決策は、より高い解像度のTimerQueueTimerを使用することです。

+0

私はその違いに興味があります...あなたは睡眠が異なって振る舞う原因を知っていますか?私はむしろタイマーを全く使用しないでしょう... –

0

新しいPCマルチコアと旧式のシングルコアはありますか?タイミング精度の違いは、複数のスレッドの使用とコンテキスト切り替えの可能性があります。

+0

新しいものは確かにデュアルコアで、古いものはありませんでした。これがタイミングの違いを引き起こすことは理にかなっていますが、デュアルコアに移行することで効率が低下したら驚くでしょう。具体的な情報に基づいていますか? –

2

主な関心事が精度の場合は、spinlockの使用を検討してください。 Sleep()関数は、少なくともxミリ秒の間、スケジューラが特定のスレッドを再スケジュールしないようにするためのヒントです。指定された時間、スレッドが正確にスリープするという保証はありません。

+0

C++/MFCライブラリにスピンロック実装はありますか? –

+0

良い時。 CPU使用量が急増し、おそらく他のアプリケーションが枯渇する...しかし、それは非リアルタイムOSによって保証され得ない10ms要求の寿命である。 – Kieveli

+0

@Kieveli:私はこのソフトウェアをPC上で実行しているので、CPU通貨で正確に支払うことができます...(でも、C++/MFCのスピンロックの最も単純な実装は何ですか?) –

1

通常、スリープ()は、スリープ値に応じて〜15ミリ秒または〜15ミリ秒の遅延をもたらします。 ハワイを見つける良い方法については、作品は次の擬似コードです:

while true do 
    print(GetTickCount()); 
    Sleep(1); 
end; 

そしてまた、それは他の人が述べたように、このコードの動作は、Windows XPとVista/Winの7

1

、たとえば、のために異なっていることが示されます、睡眠は粗い精度を有します。

私は通常、タイミングのこの種のブースト:: ASIOを使用します。

// Set up the io_service and deadline_timer 
io_service io_ 
deadline_timer timer(io_service); 

// Configure the wait period 
timer.expires_from_now(posix_time::millisec(5)); 
timer.wait(); 

ASIOは、お使いのプラットフォームのための最も効果的な実装を使用しています。 Windowsでは、重複したIOを使用していると思います。

時間を1msに設定し、「タイマー」をループするとします。 10000回の呼び出しは、通常、約10005〜10100ミリ秒です。非常に正確でクロスプラットフォームのコードです(ただし、Linuxでは精度は異なります)。

あなたの以前のPCがなぜそれほど正確であったのか説明できません。私がそれを使用したときはいつも、スリープは+/- 10msでした.PCがビジー状態であれば悪化します。

関連する問題