sleep 函数是一个非常基础且常用的函数,它的作用是让程序暂停执行指定的秒数。

(图片来源网络,侵删)
函数原型
sleep 函数主要有两种常见的实现,它们位于不同的头文件中。
a) unsigned sleep(unsigned seconds); (POSIX 标准)
这是最常用、最标准的 sleep 函数,遵循 POSIX (Portable Operating System Interface) 标准,具有很好的可移植性。
- 头文件:
unistd.h - 参数:
seconds- 一个无符号整型,表示程序需要睡眠的秒数。 - 返回值:
- 如果函数因睡眠时间到期而被唤醒,则返回 0。
- 如果函数被某个信号中断(
SIGINT,即用户按下了Ctrl+C),则返回剩余未睡的秒数。
- 特点: 这是最推荐使用的方式。
b) unsigned int sleep(unsigned int seconds); (C89 标准)
这是 C89 标准库中定义的 sleep 函数,在 Linux 环境下,它通常是对 POSIX 版本的一个简单封装。
- 头文件:
stdlib.h - 参数:
seconds- 一个无符号整型,表示睡眠的秒数。 - 返回值: 同 POSIX 版本,返回 0 或剩余秒数。
- 特点: 虽然可用,但在编写跨平台或遵循 POSIX 标准的程序时,优先使用
unistd.h中的版本。
重要提示: 在 Linux 环境下,#include <unistd.h> 是使用 sleep 函数的标准做法。

(图片来源网络,侵删)
工作原理
sleep 函数的底层实现依赖于信号。
- 当你调用
sleep(5)时,程序并不会进入一个忙等待循环(不断检查时间到了没,那样会浪费 CPU 资源)。 - 相反,
sleep函数会向操作系统内核注册一个“闹钟”,告诉内核:“请在 5 秒后唤醒我”。 - 程序会主动放弃 CPU 的使用权,进入一种可被中断的休眠状态。
- 内核会调度其他进程来使用 CPU。
- 5 秒后,内核会向你的进程发送一个
SIGALRM(Alarm Signal) 信号。 - 进程收到这个信号后,会从休眠状态被唤醒,
sleep函数执行完毕并返回 0。
信号中断:
如果在睡眠期间,你的进程收到了其他信号(SIGINT),默认情况下信号会中断 sleep 的执行。sleep 函数会立即返回,并返回剩余的秒数,信号的默认处理通常是终止程序,所以如果你不处理 SIGINT,程序会直接退出,你可能都看不到 sleep 返回的值。
代码示例
示例 1:基本用法
这个例子展示了 sleep 的基本功能,并打印返回值。
#include <stdio.h>
#include <unistd.h> // 必须包含此头文件
int main() {
printf("程序即将开始睡眠 3 秒...\n");
unsigned int sleep_seconds = 3;
unsigned int remaining = sleep(sleep_seconds);
if (remaining == 0) {
printf("睡眠 %d 秒已到期,程序继续执行,\n", sleep_seconds);
} else {
printf("睡眠被信号中断,还剩 %u 秒未睡,\n", remaining);
}
printf("程序执行完毕,\n");
return 0;
}
编译和运行:

(图片来源网络,侵删)
gcc sleep_example.c -o sleep_example ./sleep_example
预期输出:
程序即将开始睡眠 3 秒...
(等待 3 秒后)
睡眠 3 秒已到期,程序继续执行。
程序执行完毕。
示例 2:信号中断
这个例子演示了如何通过信号来中断 sleep 函数,我们使用 kill 命令来模拟发送信号。
#include <stdio.h>
#include <unistd.h>
#include <signal.h> // 用于信号处理
// 一个空的信号处理函数,什么都不做,只为了中断 sleep
void signal_handler(int sig) {
// do nothing
}
int main() {
// 设置信号 SIGINT (Ctrl+C) 的处理函数
// 这样当按下 Ctrl+C 时,程序不会退出,而是会调用 signal_handler
signal(SIGINT, signal_handler);
printf("程序即将开始睡眠 10 秒...\n");
printf("(请在 10 秒内按下 Ctrl+C 来中断睡眠)\n");
unsigned int remaining = sleep(10);
if (remaining == 0) {
printf("睡眠 10 秒已到期,\n");
} else {
printf("睡眠被信号中断,还剩 %u 秒未睡,\n", remaining);
}
printf("程序执行完毕,\n");
return 0;
}
编译和运行:
gcc sleep_interrupt.c -o sleep_interrupt ./sleep_interrupt
操作和预期输出:
- 程序启动,开始打印信息并进入 10 秒睡眠。
- 在 10 秒内,按下
Ctrl+C。 - 你会看到
sleep函数立即返回,并打印剩余的秒数。程序即将开始睡眠 10 秒... (请在 10 秒内按下 Ctrl+C 来中断睡眠) ^C睡眠被信号中断,还剩 8 秒未睡。 程序执行完毕。(注意:剩余的秒数取决于你按下
Ctrl+C的时间点)
更精确的睡眠:nanosleep
虽然 sleep 很方便,但它只精确到秒,在现代编程中,我们常常需要更高精度的休眠,比如毫秒甚至纳秒,这时,nanosleep 是更好的选择。
- 头文件:
time.h - 函数原型:
int nanosleep(const struct timespec *req, struct timespec *rem);
- 参数:
req: 指向一个timespec结构体的指针,它指定了希望睡眠的时间。struct timespec { time_t tv_sec; // 秒 long tv_nsec; // 纳秒 (1秒 = 1,000,000,000 纳秒) };rem: 一个输出参数。nanosleep被信号中断,这个指针指向的结构体会被填充上剩余需要睡眠的时间,你可以稍后再次调用nanosleep并使用这个rem参数来完成剩余的睡眠,如果不需要,可以传NULL。
- 返回值:
- 成功完成睡眠,返回 0。
- 被信号中断,返回
-1,并设置errno为EINTR,此时需要检查rem参数以获取剩余时间。
nanosleep 示例 (睡眠 1.5 秒)
#include <stdio.h>
#include <time.h> // for nanosleep
#include <unistd.h> // for (optional) sleep
int main() {
struct timespec req, rem;
// 设置请求睡眠 1 秒 和 500,000,000 纳秒 (即 1.5 秒)
req.tv_sec = 1;
req.tv_nsec = 500000000;
printf("程序即将开始睡眠 1.5 秒...\n");
int result = nanosleep(&req, &rem);
if (result == 0) {
printf("睡眠 1.5 秒已成功完成,\n");
} else {
// 被信号中断
if (errno == EINTR) {
printf("睡眠被信号中断,\n");
printf("剩余需要睡眠的时间: %ld 秒 %ld 纳秒\n", rem.tv_sec, rem.tv_nsec);
// 在这里可以重新调用 nanosleep(&rem, NULL) 来完成剩余睡眠
} else {
perror("nanosleep error"); // 打印系统错误信息
}
}
printf("程序执行完毕,\n");
return 0;
}
总结与对比
| 特性 | sleep(unsigned seconds) |
nanosleep(const struct timespec *req, ...) |
|---|---|---|
| 精度 | 秒 | 纳秒 |
| 头文件 | unistd.h |
time.h |
| 可移植性 | POSIX 标准,广泛支持 | POSIX 标准,现代 Unix/Linux 系统支持 |
| 返回值 | 剩余秒数 或 0 | 0 (成功) 或 -1 (被中断) |
| 中断处理 | 返回剩余秒数 | 通过 rem 参数返回剩余时间 |
| 适用场景 | 简单、粗略的延时,对精度要求不高 | 需要高精度延时的场景,如多媒体、游戏、网络编程等 |
最佳实践建议:
- 如果只需要秒级精度的延时,并且追求代码简洁,使用
sleep()。 - 如果需要毫秒、微秒或纳秒级的精度,或者需要处理中断后恢复睡眠,强烈推荐使用
nanosleep()。 - 避免使用
stdlib.h中的sleep,除非有特殊的历史遗留原因或兼容性需求,在 Linux C 编程中,unistd.h是标准。
