システムクロックが途中で変更された場合でも、Cocoa で 2 つの時点間の秒数を計算する

StackOverflow https://stackoverflow.com/questions/1627764

質問

私は、タイムスタンプを使用して画面上に何かが表示されている時間の統計を計算する Cocoa OS X (Leopard 10.5+) エンドユーザー プログラムを作成しています。プログラムの実行中、繰り返し NSTimer を使用して時間が定期的に計算されます。 [NSDate date] タイムスタンプを取得するために使用されます。 始める そして 仕上げる. 。2 つの日付の差を秒単位で計算するのは簡単です。

エンドユーザーまたは NTP がシステム クロックを変更すると、問題が発生します。 [NSDate date] システムクロックに依存しているため、変更されると、 仕上げる 変数は、 始める, 、時間の計算が大幅に混乱します。私の質問:

1.間の時間を正確に計算するにはどうすればよいですか 始める そして 仕上げる, 途中でシステムクロックが変更された場合でも、秒単位で?

それから何秒が経過したかを計算できるように、変化しない基準時点が必要だと考えています。たとえば、システムの稼働時間です。10.6には - (NSTimeInterval)systemUptime, 、 一部の NSProcessInfo, 、システムの稼働時間を提供します。ただし、私のアプリは 10.5 で動作する必要があるため、これは機能しません。

NSTimer を使用してタイムカウンターを作成しようとしましたが、これは正確ではありません。NSTimer にはいくつかの異なる実行モードがあり、一度に 1 つだけ実行できます。NSTimer (デフォルト) は デフォルト 実行モード。ユーザーが十分な時間にわたって UI の操作を開始すると、次のようになります。 NSEイベントトラッキング実行ループモード をスキップしてください デフォルト 実行モードでは、NSTimer の起動がスキップされる可能性があり、秒数のカウント方法が不正確になります。

また、NSTimer の秒カウンターを実行する別のスレッド (NSRunLoop) を作成して、UI の操作から遠ざけることも考えました。しかし、私はマルチスレッドの初心者なので、できれば避けたいと思っています。また、CPU が別のアプリケーション (大きな画像をレンダリングする Photoshop など) によって固定され、NSRunLoop が混乱するほど長い間保留される場合に、これが正確に機能するかどうかはわかりません。 NSタイマー。

助けていただければ幸いです。:)

役に立ちましたか?

解決 3

私はこれを使用してこれを行う方法を考え出しました 稼働時間() C 関数。で提供されます。 <CoreServices/CoreServices.h>. 。これは絶対時間 (CPU 固有) を返します。これは継続時間 (ミリ秒またはナノ秒) に簡単に変換できます。詳細はこちら: http://www.meandmark.com/timingpart1.html (稼働時間についてはパート 3 を参照してください)

入手できませんでした mach_absolute_time() おそらく私の知識が不足していて、Web 上でそれに関するドキュメントをあまり見つけることができなかったため、適切に動作しませんでした。と同じタイムを掴んでいるようです UpTime(), 、しかしそれをダブルに変換すると、私は唖然としました。

[[NSApp currentEvent] timestamp] 動作しましたが、アプリケーションが NSEvents を受信して​​いた場合に限りました。アプリケーションがフォアグラウンドに移行すると、イベントを受信できなくなります。 [[NSApp currentEvent] timestamp] エンドユーザーが再度アプリを操作することを決定するまで、NSTimer 起動メソッドで同じ古いタイムスタンプを繰り返し返し続けるだけです。

マークとマイク、ご協力ありがとうございました!あなたたちは間違いなく、答えにつながる正しい方向に私を送ってくれました。:)

他のヒント

このコードを駆動しているものに応じて、2つの選択肢があります:

  • 絶対的な精度を得るには、 mach_absolute_time() を使用します。関数を呼び出したポイント間の正確な時間間隔を示します。
  • しかし、GUIアプリでは、これは実際には望ましくないことがよくあります。代わりに、期間を開始および終了したイベントの時間差が必要です。その場合、[[NSApp currentEvent] timestamp]
  • を比較します

さて、これはロングショットですが、Snow Leopardで利用可能なNSSystemClockDidChangeNotificationのようなものを実装してみてください。

というのは、これは奇妙な考えであり、間違いなく非決定論的であるためです。しかし、プログラムの実行中にウォッチドッグスレッドが実行されている場合はどうでしょうか。このスレッドは、n秒ごとにシステム時間を読み取り、保存します。議論のために、5秒にしましょう。したがって、5秒ごとに、前回の読み取り値と現在のシステム時刻を比較します。 <!> quot;十分に大きい<!> quotがある場合;差異(<!> quot;十分に大きい<!> quot;は、プロセススケジューリングとスレッドの優先順位付けの非決定性を考慮して、5より大きくする必要がありますが、大きすぎない必要があります) 、大幅な時間変更があったという通知を投稿します。 <!> quot;十分な大きさの<!> quot;を構成する値をファジングする必要があります。 (または、時計が以前の時間にリセットされた場合は十分に小さい)精度のニーズのため。

これは一種のハッキングですが、他の解決策がない限り、どう思いますか?それ、またはそのような何かがあなたの問題を解決するかもしれませんか?

編集

さて、元の質問を修正して、マルチスレッドに慣れていないのでウォッチドッグスレッドを使用したくないと言ったとします。私はあなたが慣れているよりも少し高度なことをすることへの恐怖を理解していますが、これが唯一の解決策になるかもしれません。その場合、少し読む必要があるかもしれません。 =)

そして、ええ、Photoshopのようなものがプロセッサから不要なものを追い出すことが問題であることを知っています。別の(さらに複雑な)解決策は、ウォッチドッグスレッドを使用する代わりに、最優先の個別のウォッチドッグプロセスを使用して、プロセッサに対する耐性を高めることです。ペギング。しかし、これも非常に複雑になっています。

最終編集

完全を期すために、上記の他のアイデアはすべて残しておきますが、システムの稼働時間を使用することも、これに対処する有効な方法になると思われます。 [[NSProcessInfo processInfo] systemUptime]は10.6+でのみ機能するため、mach_absolute_time()を呼び出すことができます。その機能にアクセスするには、#include <mach/mach_time.h>だけです。これは、NSProcessInfoによって返される値と同じでなければなりません。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top