如果您看一下clock_gettime()函数,它在所有BSD 中都可用并且实际上被定义为POSIX 标准的一部分,您会发现至少支持三种类型的时钟(许多系统支持的时钟不止这些时钟) ,但实际上 POSIX 标准只要求存在一个,所有其他都是可选的):
CLOCK_REALTIME - POSIX 要求它存在。这是挂钟。
CLOCK_MONOTONIC - 不知道这是什么(以及 SI 秒的含义),但我知道这个时钟永远不会向后跳,它只能单调增加值。
CLOCK_UPTIME - 我看不出这与 CLOCK_MONOTONIC 有什么不同(正常运行时间也永远不会向后跳),但至少我知道内核启动时这个时钟从零开始(而它没有定义内核启动时 CLOCK_MONOTONIC 的初始值是多少) )
让我们暂时忽略其他时钟。CLOCK_REALTIME 不能保证单调向上计数,对吧?这是实际的“系统时间”。我可以随意更改系统时间。我可以将它设置为过去 3 个月或未来 5 年,每次我的系统使用网络上的 NTP 服务器同步时间时,时间可能会向前或向后跳跃。
现在我们在 BSD 系统中有两个休眠函数。sleep()和nanosleep()。我不确定,但我希望 sleep() 在 nanosleep 之上实现,毕竟我可以通过使用 nanosleep() 轻松模拟 sleep() 并且只在 struct timespec 中设置秒数,保持纳秒为零.
我在很多资料中读到,这些函数实际上是通过计算唤醒时间来工作的(获取当前时间,添加睡眠量),如果当前时间晚于唤醒时间,系统将定期检查时间,如果是这样,它将再次唤醒线程。仅在间隔中检查这一事实是手册页说当前睡眠将至少睡眠这段时间的原因(仅在被信号中断时更短),但它可能会睡眠更长时间(取决于多久系统检查我们是否已经超过了唤醒时间,并且取决于调度程序允许该线程再次运行之前需要多长时间)。
这对我来说是完全理智的......但是有一个问题一直困扰着我:
根据各种来源,睡眠(至少是 nanosleep)在内部使用 CLOCK_REALTIME 作为时钟。这意味着,如果告诉 nanosleep() 休眠 30 秒,然后将我的系统时钟更改为未来 1 小时,线程将几乎立即唤醒(未来 1 小时远早于唤醒时间 nanosleep( )计算)。这也完全没问题。但是,如果我说在 30 秒后醒来,然后用户发现他的系统时钟提前一小时并将他的时钟向后设置一小时,会发生什么?然后我的线程会休眠 1 小时 30 秒?因为那将是相当糟糕的。