有时,在一个慵懒的周末下午,我会使用 apt-get 来拉下某些东西的源代码,然后开始 grep 以寻找一定会很有趣的东西。这是其中一个下午,我发现了一些愚蠢的事情。在 bash 中寻找 time_t 的用途时,我发现了一个名为“time_since_start”的变量。呃哦。
bash 支持一个名为“SECONDS”的动态变量(打赌你不知道 – 我不知道),它被记录为“自 shell 调用以来的秒数”。很抱歉,这不是真的。你完全可以让它变成负数,因为它是基于wall time的。只需将系统时钟调回即可。
root@rpi4b:/tmp# systemctl 停止 chrony root@rpi4b:/tmp# echo $SECONDS 11 root@rpi4b:/tmp# date -s "2023-01-01 00:00:00Z" 太平洋标准时间 2022 年 12 月 31 日星期六 04:00:00 root@rpi4b:/tmp# echo $SECONDS -2500987
这是一个极端的演示,但每次我们有闰秒时都会发生倒退的墙时间。诚然,我们目前正处于漫长的干旱时期,但它可能会在我们有生之年再次发生。差别只有一秒钟,但如果有人依赖 shell 脚本中的那个值,它可能会破坏某些东西。
或者,如果机器由于某种原因出现了一个非常糟糕的时间(你的硬件人员是否在BOM上降价并在全新的数千美元服务器上放弃了 25 美分的实时时钟?), shell 开始运行,然后 chrony(或其他)修复它?同样的交易,只有这样它可能不是一秒钟。可能更多。
在机器出现过去日期然后向前跳转的情况下,在修复之前仍在运行的 shell 上的 SECONDS 将比它应该的大得多。我很确定每个 Raspberry Pi 在第一次出现时都会认为时间 = 0,因为板上没有 RTC。在其中一个上运行“上次重启”以了解我的意思。
我还应该提到 bash 会做其他类似的事情来(尝试)查看已经过了多少时间。你有没有注意到它有时会说“你有新邮件”,对于那些真正使用老式邮件传递的少数人来说?它仅在经过足够的时间后才进行检查。我想“负持续时间”将意味着不再检查。
这里的教训是,墙上的时间不能用来衡量持续时间。任何时候你看到有人减去挂钟时间(即来自 time() 或 gettimeofday() 的任何东西),请担心。如果您的设备有单调时钟,请使用单调时钟测量持续时间。实际值是一个黑盒子,但您可以从另一个中减去一个,然后计算出它们的单位已经过去了多少……差不多。
如果您可以选择并且机器有可能进入休眠状态,请务必注意您使用的单调时钟。 “我一直在运行的单调时间”和“自启动以来的单调时间”在此类设备上是两种不同的东西。
这是今天的奖金“在这里砸头”时刻。来自典型 Linux 机器上 clock_gettime 的手册页:
CLOCK_MONOTONIC:“这个时钟不计算系统暂停的时间。”
这是当前 (Ventura) Mac 上的相同位:
CLOCK_MONOTONIC:“……并且会在系统休眠时继续递增。”
啊,是的,便携性。生活中所有软件问题的起因和解决方案。