只需使用Mach Time。
它是公共 API,可以在 macOS、iOS 和 tvOS 上运行,并且可以在沙箱中运行。
Mach Time 返回一个我通常称之为“时钟滴答”的抽象时间单位。时钟滴答的长度是系统特定的,取决于 CPU。在当前的英特尔系统上,时钟滴答实际上恰好是一纳秒,但您不能依赖它(对于 ARM 可能不同,对于 PowerPC CPU 肯定不同)。系统还可以告诉您将时钟滴答转换为纳秒和纳秒转换为时钟滴答的转换因子(这个因子是静态的,它在运行时永远不会改变)。当您的系统启动时,时钟从 开始,0
然后随着之后的每个时钟滴答声而单调增加,因此您也可以使用 Mach Time 来获取系统的正常运行时间(当然,正常运行时间是单调的!)。
这是一些代码:
#include <stdio.h>
#include <inttypes.h>
#include <mach/mach_time.h>
int main ( ) {
uint64_t clockTicksSinceSystemBoot = mach_absolute_time();
printf("Clock ticks since system boot: %"PRIu64"\n",
clockTicksSinceSystemBoot
);
static mach_timebase_info_data_t timebase;
mach_timebase_info(&timebase);
// Cast to double is required to make this a floating point devision,
// otherwise it would be an interger division and only the result would
// be converted to floating point!
double clockTicksToNanosecons = (double)timebase.numer / timebase.denom;
uint64_t systemUptimeNanoseconds = (uint64_t)(
clockTicksToNanosecons * clockTicksSinceSystemBoot
);
uint64_t systemUptimeSeconds = systemUptimeNanoseconds / (1000 * 1000 * 1000);
printf("System uptime: %"PRIu64" seconds\n", systemUptimeSeconds);
}
您还可以让线程休眠,直到达到特定的马赫时间。这是一些代码:
// Sleep for 750 ns
uint64_t machTimeNow = mach_absolute_time();
uint64_t clockTicksToSleep = (uint64_t)(750 / clockTicksToNanosecons);
uint64_t machTimeIn750ns = machTimeNow + clockTicksToSleep;
mach_wait_until(machTimeIn750ns);
由于马赫时间与任何挂钟时间无关,您可以随意调整系统日期和时间设置,这不会对马赫时间产生任何影响。
但是,有一个特殊的考虑因素可能会使 Mach Time 不适用于某些用例:当您的系统处于睡眠状态时,CPU 时钟没有运行!因此,如果您让线程等待 5 分钟,并且在 1 分钟后系统进入睡眠状态并保持睡眠状态 30 分钟,那么在系统唤醒后线程仍在等待另外 4 分钟,因为 30 分钟的睡眠时间不算在内!在此期间 CPU 时钟也处于静止状态。然而在其他情况下,这正是你想要发生的。
马赫时间也是一种非常精确的测量时间的方法。这是一些显示该任务的代码:
// Measure time
uint64_t machTimeBegin = mach_absolute_time();
sleep(1);
uint64_t machTimeEnd = mach_absolute_time();
uint64_t machTimePassed = machTimeEnd - machTimeBegin;
uint64_t timePassedNS = (uint64_t)(
machTimePassed * clockTicksToNanosecons
);
printf("Thread slept for: %"PRIu64" ns\n", timePassedNS);
您会看到线程没有休眠一秒钟,这是因为将线程置于休眠状态需要一些时间才能再次唤醒它,即使在唤醒时,如果所有内核都不会立即获得 CPU 时间那时已经在忙着运行一个线程。
更新 (2018-09-26)
由于 macOS 10.12 (Sierra) 也存在mach_continuous_time
. mach_continuous_time
和之间的唯一区别mach_absolute_time
是,当系统处于睡眠状态时,持续时间也会提前。因此,如果到目前为止这是一个问题并且是不使用 Mach Time 的原因,10.12 及更高版本提供了解决此问题的方法。用法与上面描述的完全相同。
同样从 macOS 10.9 (Mavericks) 开始,有一个mach_approximate_time
,在 10.12 中还有一个mach_continuous_approximate_time
. 这两个是相同的mach_absolute_time
,mach_continuous_time
唯一的区别是它们更快但不太准确。标准函数需要调用内核,因为内核负责马赫时间。这样的调用有点昂贵,尤其是在已经有Meltdown修复的系统上。近似版本不必总是调用内核。他们在用户空间中使用一个只与内核时钟不时同步的时钟,以防止它运行得太远不同步,但总是可能出现小的偏差,因此它只是“近似的”马赫时间。