在Catalina上违反单调的时间期望

2020-10-21 07:22:55

单调的时间是这样一种东西,除非你被不使用它咬了,否则你可能不会了解它。拥有一个只会向上走的时钟的全部意义在于,这个系统与你达成了一个协议,那就是它永远不会倒退。然后,您可以使用它来测量持续时间,而不管人类可读的(墙时间)可能在做什么。

也就是说,即使计算机管理员在计算过程中将系统时间倒退了55秒,您仍然可以可靠地计数出实际的60秒,并且仍然可以等待合适的时间。如果您使用系统时钟(挂钟时间)这样做,那么它将受到该调整的影响。

让我们假设您是一名开发人员,这就是您。你用time()或gettimeofday()或类似的东西计算持续时间,然后闰秒把你的系统搞得一团糟,或者有人严重破坏了你的计时,你的机器向前跳了17秒,然后又向后跳了17秒。您吸取了教训并开始使用单调计时器。

现在,让我们假设你已经转向在笔记本电脑和其他有时会进入睡眠状态的系统上做事情。您希望跟踪机器实际处于活动状态而不是绝对时间的持续时间。在这样一台机器上,您转到lock_gettime的手册页,您会发现:

CLOCK_UPTIME_RAW:以与CLOCK_MONTOTION_RAW相同的方式单调递增的时钟,但在系统休眠时不会递增。返回值与应用适当的mach_timebase转换后的mach_Absolute_time()的结果相同。

好啊,好啊,好啊!听起来很棒,对吧?它向上滴答作响,从不倒退,而且只在机器唤醒时滴答作响。听起来太棒了!

你围绕着这一点建立你的东西,事情在一段时间内是好的。但是有一天,您注意到您的代码在某些情况下非常不愉快。事实上,看起来你的东西在非常紧的圈子里运行了不合理的时间。它应该在这个紧密的循环中旋转至多几毫秒,但在这里它要转几分钟,甚至几个小时!

然后有一天,你会注意到,只有在电池电量低于50%的情况下,才会在系统深度睡眠一小时或更长时间后出现这种情况。这就是你看到它的时候:在更新版本的操作系统上,当机器重新唤醒时,计时器会重置!

现在您知道了为什么代码会100%地占用该自旋循环中的CPU,并且会一直运行,直到机器的实际正常运行时间大约翻了一番。也就是说,如果你让它在45分钟的正常运行时间后用低电量的电池休眠,然后过一段时间唤醒它,它会像这样再旋转45分钟。

根据我从一位读者那里得到的一份报告,这在运行Catalina的Mac上似乎非常真实,而在Mojave上却不是这样。您也可以看到在哪里向libuv和llvm报告了这一点。

我还没有尝试在我自己的Mac电脑上复制这一点,因为这需要大量的电池消耗,然后需要很长时间的睡眠,而且我还有其他事情要处理这些盒子。根据那些错误报告,我愿意相信这是真的。