7

如果您看一下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 秒?因为那将是相当糟糕的。

4

2 回答 2

4

据我所知,睡眠功能通常更像是一个递减计数器。您说“睡眠 10 秒”,这在调度程序中转换为“睡眠 1000 个计划滴答”,然后每次调度程序检查睡眠进程时,它都会减少剩余时间。

通过这种方式,睡眠时间将始终是实际睡眠时间,而不是一直睡到未来的某个时间。这样做的原因正如您所怀疑的那样,如果我们在未来选择一个时间,我们可能永远不会到达那里(或者可能会在意想不到的时间内到达那里)。这与您希望在程序中使用 sleep 的目的一致。它并不意味着进行类似日历的计算。

你也可以做一个简单的测试,让程序休眠 30 秒,使用 nix 的“time”命令来计算函数运行的时间,然后在它开始后将你的系统时钟改回 5 分钟,看看会发生什么。

于 2009-01-09T12:06:14.630 回答
2

该线程将检查一个内部计数器,该计数器设置为睡眠的持续时间而不是睡眠的终点。使用的内部计数器与当前系统时间无关,因此如果系统时间发生任何变化,也不会受到影响。

于 2009-01-09T12:22:15.550 回答