iOS/OS Xにおける高精度タイマ
4862 ワード
原文住所:https://developer.apple.com/library/content/technotes/tn2169/_index.html
iOS/OS Xにおける高精度タイマ
...
Timerの動作原理
iOSとOS Xには、特定の時間を待つことができるAPIがたくさんあります.これらのAPIは、異なるタイプのパラメータを持つCまたはObjective Cによって書かれている可能性がありますが、カーネルでは同じコードで終了します.各タイマに関連するapiは、カーネルに今から10秒など、どのくらい待つ必要があるかを教えます.カーネルは各スレッドを監視し続け、タイマリクエストが来ると、そのスレッドは「10秒後に実行したい」とマークされます.
カーネルはできるだけ中央プロセッサと同期しようとするので、他のタスクが実行されていない場合は、CPUを10秒間寝させ、現在のスレッドを起動して実行します.
もちろん、それは最良の状況であり、実際の光景ではそう簡単ではありません.実行を待つスレッドが多く、タイマ要求があるスレッドが多く、カーネルはすべてのタイマを管理する必要があります.わずかなcpuコアで数万個のスレッドが実行されると、タイマの不正確さが容易に見えます.
高精度のタイマがどのように動作するか
従来のタイマと高精度タイマの唯一の違いは、スレッドのスケジューリングクラスです.リアルタイムスケジューリング状態でのスレッドの優先処理.実行する必要がある場合は、キューの一番前に走ります.10秒後に他のスレッドが実行される場合、リアルタイムスレッドは通常優先的に実行されます.
スレッドをリアルタイムスケジューリング状態にする方法
Listing 1 The following code will move a pthread to the real time scheduling class
どのスケジューリングAPIを使用すればいいですか?
上記のように、すべてのタイマ関数はカーネルの同じ場所で終了します.しかし、いくつかはもっと効果的です.mach_をお勧めしますwait_until()は、この関数がすべてのタイマAPIで最小のオーバーヘッドを有する.でもmach_があればwait_until()が満たされない特定のニーズ、例えば条件変数を待つ必要がある場合は、適切なAPIを使用することを考慮することができます.
Listing 2 This example code demonstrates using mach_wait_until() to wait exactly 10 seconds.
iOS/OS Xにおける高精度タイマ
...
Timerの動作原理
iOSとOS Xには、特定の時間を待つことができるAPIがたくさんあります.これらのAPIは、異なるタイプのパラメータを持つCまたはObjective Cによって書かれている可能性がありますが、カーネルでは同じコードで終了します.各タイマに関連するapiは、カーネルに今から10秒など、どのくらい待つ必要があるかを教えます.カーネルは各スレッドを監視し続け、タイマリクエストが来ると、そのスレッドは「10秒後に実行したい」とマークされます.
カーネルはできるだけ中央プロセッサと同期しようとするので、他のタスクが実行されていない場合は、CPUを10秒間寝させ、現在のスレッドを起動して実行します.
もちろん、それは最良の状況であり、実際の光景ではそう簡単ではありません.実行を待つスレッドが多く、タイマ要求があるスレッドが多く、カーネルはすべてのタイマを管理する必要があります.わずかなcpuコアで数万個のスレッドが実行されると、タイマの不正確さが容易に見えます.
高精度のタイマがどのように動作するか
従来のタイマと高精度タイマの唯一の違いは、スレッドのスケジューリングクラスです.リアルタイムスケジューリング状態でのスレッドの優先処理.実行する必要がある場合は、キューの一番前に走ります.10秒後に他のスレッドが実行される場合、リアルタイムスレッドは通常優先的に実行されます.
スレッドをリアルタイムスケジューリング状態にする方法
Listing 1 The following code will move a pthread to the real time scheduling class
#include
#include
#include
void move_pthread_to_realtime_scheduling_class(pthread_t pthread)
{
mach_timebase_info_data_t timebase_info;
mach_timebase_info(&timebase_info);
const uint64_t NANOS_PER_MSEC = 1000000ULL;
double clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC;
thread_time_constraint_policy_data_t policy;
policy.period = 0;
policy.computation = (uint32_t)(5 * clock2abs); // 5 ms of work
policy.constraint = (uint32_t)(10 * clock2abs);
policy.preemptible = FALSE;
int kr = thread_policy_set(pthread_mach_thread_np(pthread_self()),
THREAD_TIME_CONSTRAINT_POLICY,
(thread_policy_t)&policy,
THREAD_TIME_CONSTRAINT_POLICY_COUNT);
if (kr != KERN_SUCCESS) {
mach_error("thread_policy_set:", kr);
exit(1);
}
}
どのスケジューリングAPIを使用すればいいですか?
上記のように、すべてのタイマ関数はカーネルの同じ場所で終了します.しかし、いくつかはもっと効果的です.mach_をお勧めしますwait_until()は、この関数がすべてのタイマAPIで最小のオーバーヘッドを有する.でもmach_があればwait_until()が満たされない特定のニーズ、例えば条件変数を待つ必要がある場合は、適切なAPIを使用することを考慮することができます.
Listing 2 This example code demonstrates using mach_wait_until() to wait exactly 10 seconds.
#include
#include
static const uint64_t NANOS_PER_USEC = 1000ULL;
static const uint64_t NANOS_PER_MILLISEC = 1000ULL * NANOS_PER_USEC;
static const uint64_t NANOS_PER_SEC = 1000ULL * NANOS_PER_MILLISEC;
static mach_timebase_info_data_t timebase_info;
static uint64_t abs_to_nanos(uint64_t abs) {
return abs * timebase_info.numer / timebase_info.denom;
}
static uint64_t nanos_to_abs(uint64_t nanos) {
return nanos * timebase_info.denom / timebase_info.numer;
}
void example_mach_wait_until(int argc, const char * argv[])
{
mach_timebase_info(&timebase_info);
uint64_t time_to_wait = nanos_to_abs(10ULL * NANOS_PER_SEC);
uint64_t now = mach_absolute_time();
mach_wait_until(now + time_to_wait);
}