105. sleep - 让进程休眠指定秒数 見出しへのリンク
1. 函数介绍 見出しへのリンク
sleep
是一个标准 C 库函数,用于让当前进程休眠(挂起)指定的秒数。在此期间,进程不会占用 CPU 时间,直到休眠时间结束或被信号中断。
2. 函数原型 見出しへのリンク
#include <unistd.h>
unsigned int sleep(unsigned int seconds);
3. 功能 見出しへのリンク
让调用进程休眠指定的秒数。这是一个简单的延时函数,常用于程序中的定时控制、轮询间隔控制等场景。
4. 参数 見出しへのリンク
unsigned int seconds
: 要休眠的秒数- 0: 立即返回
- 正整数: 休眠指定的秒数
5. 返回值 見出しへのリンク
- 如果休眠完成:返回 0
- 如果被信号中断:返回剩余未休眠的秒数
- 注意:在某些系统上,即使被信号中断也可能返回 0
6. 相似函数,或关联函数 見出しへのリンク
usleep()
: 微秒级休眠(已废弃,推荐使用nanosleep
)nanosleep()
: 纳秒级休眠,更精确的定时函数alarm()
: 设置定时器信号setitimer()
: 设置间隔定时器clock_nanosleep()
: 基于特定时钟的休眠select()
,poll()
: 带超时的 I/O 多路复用函数
7. 示例代码 見出しへのリンク
示例1:基本使用 - 简单休眠 見出しへのリンク
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
void simple_sleep_demo() {
printf("=== sleep 基本使用演示 ===\n");
printf("开始时间: ");
fflush(stdout);
system("date");
printf("休眠 3 秒...\n");
unsigned int remaining = sleep(3);
printf("休眠结束,剩余时间: %u 秒\n", remaining);
printf("结束时间: ");
fflush(stdout);
system("date");
}
int main() {
simple_sleep_demo();
return 0;
}
示例2:信号中断处理 見出しへのリンク
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <string.h>
volatile sig_atomic_t interrupted = 0;
void signal_handler(int sig) {
printf("\n收到信号 %d\n", sig);
interrupted = 1;
}
void signal_interrupt_demo() {
printf("=== 信号中断演示 ===\n");
// 设置信号处理
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
printf("进程 PID: %d\n", getpid());
printf("请在 5 秒内按 Ctrl+C 测试信号中断\n");
printf("开始休眠 5 秒...\n");
unsigned int remaining = sleep(5);
if (remaining > 0) {
printf("休眠被中断,剩余时间: %u 秒\n", remaining);
} else {
printf("休眠正常完成\n");
}
// 恢复默认信号处理
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
}
int main() {
signal_interrupt_demo();
return 0;
}
示例3:精确时间测量 見出しへのリンク
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
double time_diff(struct timeval *end, struct timeval *start) {
return (end->tv_sec - start->tv_sec) +
(end->tv_usec - start->tv_usec) / 1000000.0;
}
void precise_timing_demo() {
printf("=== 精确时间测量演示 ===\n");
struct timeval start, end;
unsigned int remaining;
// 测试不同休眠时间
int test_times[] = {1, 2, 3, 5};
int test_count = sizeof(test_times) / sizeof(test_times[0]);
for (int i = 0; i < test_count; i++) {
printf("\n测试休眠 %d 秒:\n", test_times[i]);
if (gettimeofday(&start, NULL) == -1) {
perror("获取开始时间失败");
continue;
}
printf(" 开始时间: %ld.%06ld\n", start.tv_sec, start.tv_usec);
remaining = sleep(test_times[i]);
if (gettimeofday(&end, NULL) == -1) {
perror("获取结束时间失败");
continue;
}
printf(" 结束时间: %ld.%06ld\n", end.tv_sec, end.tv_usec);
printf(" 实际耗时: %.6f 秒\n", time_diff(&end, &start));
printf(" 剩余时间: %u 秒\n", remaining);
double accuracy = (time_diff(&end, &start) / test_times[i]) * 100;
printf(" 时间精度: %.2f%%\n", accuracy);
}
}
int main() {
precise_timing_demo();
return 0;
}
}
示例4:定时任务和轮询 見出しへのリンク
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
volatile sig_atomic_t keep_running = 1;
void signal_handler(int sig) {
printf("\n收到终止信号,准备退出...\n");
keep_running = 0;
}
void polling_task_demo() {
printf("=== 定时任务演示 ===\n");
// 设置信号处理
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);
printf("启动定时任务 (按 Ctrl+C 退出):\n");
printf("进程 PID: %d\n", getpid());
int counter = 0;
while (keep_running) {
time_t now = time(NULL);
printf("[%ld] 执行任务 #%d\n", (long)now, ++counter);
// 模拟任务执行
printf(" 执行中...\n");
sleep(1); // 模拟任务耗时
if (!keep_running) break;
printf(" 休眠 2 秒等待下次执行...\n");
unsigned int remaining = sleep(2);
if (remaining > 0) {
printf(" 休眠被中断,剩余 %u 秒\n", remaining);
break;
}
}
printf("定时任务已停止\n");
// 恢复默认信号处理
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
}
int main() {
polling_task_demo();
return 0;
}
8. 高级应用示例 見出しへのリンク
示例5:睡眠函数比较 見出しへのリンク
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
#ifdef _POSIX_C_SOURCE
#include <signal.h>
#endif
double get_current_time() {
struct timeval tv;
gettimeofday(&tv, NULL);
return tv.tv_sec + tv.tv_usec / 1000000.0;
}
void compare_sleep_functions() {
printf("=== 睡眠函数比较 ===\n");
const int sleep_duration = 1; // 1秒
const int iterations = 5;
double start_time, end_time;
printf("测试 %d 次 %d 秒的休眠:\n", iterations, sleep_duration);
printf("%-12s %-10s %-12s %s\n", "函数", "期望时间", "实际时间", "精度");
printf("%-12s %-10s %-12s %s\n", "----", "----", "----", "----");
// 测试 sleep
double sleep_total = 0;
for (int i = 0; i < iterations; i++) {
start_time = get_current_time();
sleep(sleep_duration);
end_time = get_current_time();
double actual_time = end_time - start_time;
sleep_total += actual_time;
}
double sleep_avg = sleep_total / iterations;
double sleep_accuracy = (sleep_avg / sleep_duration) * 100;
printf("%-12s %-10d %-12.6f %.2f%%\n", "sleep", sleep_duration, sleep_avg, sleep_accuracy);
// 测试 usleep (如果可用)
#ifdef _POSIX_C_SOURCE
double usleep_total = 0;
for (int i = 0; i < iterations; i++) {
start_time = get_current_time();
usleep(sleep_duration * 1000000); // 微秒
end_time = get_current_time();
double actual_time = end_time - start_time;
usleep_total += actual_time;
}
double usleep_avg = usleep_total / iterations;
double usleep_accuracy = (usleep_avg / sleep_duration) * 100;
printf("%-12s %-10d %-12.6f %.2f%%\n", "usleep", sleep_duration, usleep_avg, usleep_accuracy);
#endif
// 测试 nanosleep (如果可用)
#if defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 199309L
double nanosleep_total = 0;
struct timespec req = {sleep_duration, 0};
struct timespec rem;
for (int i = 0; i < iterations; i++) {
start_time = get_current_time();
nanosleep(&req, &rem);
end_time = get_current_time();
double actual_time = end_time - start_time;
nanosleep_total += actual_time;
}
double nanosleep_avg = nanosleep_total / iterations;
double nanosleep_accuracy = (nanosleep_avg / sleep_duration) * 100;
printf("%-12s %-10d %-12.6f %.2f%%\n", "nanosleep", sleep_duration, nanosleep_avg, nanosleep_accuracy);
#endif
}
int main() {
compare_sleep_functions();
return 0;
}
示例6:自适应休眠控制 見出しへのリンク
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/time.h>
typedef struct {
double target_interval; // 目标间隔时间(秒)
double last_time; // 上次执行时间
double accumulated_error; // 累积误差
} adaptive_sleeper_t;
void adaptive_sleeper_init(adaptive_sleeper_t *sleeper, double interval) {
sleeper->target_interval = interval;
sleeper->last_time = 0;
sleeper->accumulated_error = 0;
}
int adaptive_sleep(adaptive_sleeper_t *sleeper) {
struct timeval tv;
gettimeofday(&tv, NULL);
double current_time = tv.tv_sec + tv.tv_usec / 1000000.0;
if (sleeper->last_time == 0) {
sleeper->last_time = current_time;
return 0; // 第一次调用,不需要休眠
}
double elapsed = current_time - sleeper->last_time;
double target_time = sleeper->last_time + sleeper->target_interval;
double sleep_time = target_time - current_time + sleeper->accumulated_error;
if (sleep_time > 0) {
unsigned int sleep_seconds = (unsigned int)sleep_time;
if (sleep_seconds > 0) {
unsigned int remaining = sleep(sleep_seconds);
sleeper->accumulated_error = sleep_time - sleep_seconds;
if (remaining > 0) {
sleeper->accumulated_error += remaining;
return 1; // 被中断
}
}
} else {
// 超时了,记录负误差
sleeper->accumulated_error += sleep_time;
}
sleeper->last_time = current_time;
return 0;
}
void adaptive_sleep_demo() {
printf("=== 自适应休眠演示 ===\n");
adaptive_sleeper_t sleeper;
adaptive_sleeper_init(&sleeper, 2.0); // 2秒间隔
printf("目标间隔: 2.0 秒\n");
printf("开始自适应休眠循环 (按 Ctrl+C 退出):\n");
int count = 0;
while (count < 10) {
if (adaptive_sleep(&sleeper) != 0) {
printf("休眠被中断\n");
break;
}
struct timeval tv;
gettimeofday(&tv, NULL);
printf("第 %d 次执行: %ld.%06ld\n", ++count, tv.tv_sec, tv.tv_usec);
// 模拟不同长度的任务
if (count % 3 == 0) {
printf(" 执行长任务 (0.5秒)...\n");
usleep(500000); // 0.5秒
} else {
printf(" 执行短任务 (0.1秒)...\n");
usleep(100000); // 0.1秒
}
}
printf("自适应休眠演示完成\n");
}
int main() {
adaptive_sleep_demo();
return 0;
}
示例7:睡眠工具和监控 見出しへのリンク
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <signal.h>
#include <string.h>
typedef enum {
SLEEP_MODE_BASIC,
SLEEP_MODE_INTERRUPTIBLE,
SLEEP_MODE_MEASURED
} sleep_mode_t;
volatile sig_atomic_t sleep_interrupted = 0;
void interrupt_handler(int sig) {
printf("\n睡眠被信号 %d 中断\n", sig);
sleep_interrupted = 1;
}
void show_sleep_help() {
printf("睡眠工具使用说明:\n");
printf(" sleep <秒数> - 基本休眠\n");
printf(" sleep -i <秒数> - 可中断休眠\n");
printf(" sleep -m <秒数> - 测量休眠时间\n");
printf(" sleep -h - 显示此帮助\n");
printf("\n示例:\n");
printf(" sleep 5 - 休眠 5 秒\n");
printf(" sleep -i 10 - 可中断休眠 10 秒\n");
printf(" sleep -m 3 - 测量 3 秒休眠\n");
}
unsigned int measured_sleep(unsigned int seconds) {
struct timeval start, end;
if (gettimeofday(&start, NULL) == -1) {
perror("获取开始时间失败");
return sleep(seconds);
}
printf("开始时间: %ld.%06ld\n", start.tv_sec, start.tv_usec);
unsigned int remaining = sleep(seconds);
if (gettimeofday(&end, NULL) == -1) {
perror("获取结束时间失败");
return remaining;
}
printf("结束时间: %ld.%06ld\n", end.tv_sec, end.tv_usec);
double elapsed = (end.tv_sec - start.tv_sec) +
(end.tv_usec - start.tv_usec) / 1000000.0;
printf("实际耗时: %.6f 秒\n", elapsed);
printf("时间精度: %.2f%%\n", (elapsed / seconds) * 100);
return remaining;
}
int sleep_tool(int argc, char *argv[]) {
if (argc < 2) {
show_sleep_help();
return 1;
}
sleep_mode_t mode = SLEEP_MODE_BASIC;
unsigned int seconds = 0;
int opt;
// 简单的参数解析
if (strcmp(argv[1], "-h") == 0) {
show_sleep_help();
return 0;
}
if (strcmp(argv[1], "-i") == 0) {
mode = SLEEP_MODE_INTERRUPTIBLE;
if (argc < 3) {
fprintf(stderr, "错误: -i 需要指定秒数\n");
return 1;
}
seconds = atoi(argv[2]);
} else if (strcmp(argv[1], "-m") == 0) {
mode = SLEEP_MODE_MEASURED;
if (argc < 3) {
fprintf(stderr, "错误: -m 需要指定秒数\n");
return 1;
}
seconds = atoi(argv[2]);
} else {
seconds = atoi(argv[1]);
}
if (seconds == 0) {
fprintf(stderr, "错误: 无效的秒数\n");
return 1;
}
printf("进程 PID: %d\n", getpid());
switch (mode) {
case SLEEP_MODE_BASIC:
printf("开始休眠 %u 秒...\n", seconds);
sleep(seconds);
printf("休眠完成\n");
break;
case SLEEP_MODE_INTERRUPTIBLE:
printf("开始可中断休眠 %u 秒...\n", seconds);
signal(SIGINT, interrupt_handler);
signal(SIGTERM, interrupt_handler);
unsigned int remaining = sleep(seconds);
if (sleep_interrupted || remaining > 0) {
printf("休眠被中断,剩余时间: %u 秒\n", remaining);
} else {
printf("休眠正常完成\n");
}
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
break;
case SLEEP_MODE_MEASURED:
printf("开始测量休眠 %u 秒...\n", seconds);
measured_sleep(seconds);
break;
}
return 0;
}
void interactive_sleep_tool() {
unsigned int seconds;
int choice;
while (1) {
printf("\n=== 交互式睡眠工具 ===\n");
printf("1. 普通休眠\n");
printf("2. 可中断休眠\n");
printf("3. 测量休眠\n");
printf("4. 循环休眠\n");
printf("5. 显示系统时间\n");
printf("0. 退出\n");
printf("请选择操作: ");
if (scanf("%d", &choice) != 1) {
printf("输入无效\n");
while (getchar() != '\n'); // 清空输入缓冲区
continue;
}
switch (choice) {
case 1:
printf("输入休眠秒数: ");
if (scanf("%u", &seconds) == 1) {
printf("开始休眠 %u 秒...\n", seconds);
sleep(seconds);
printf("休眠完成\n");
}
break;
case 2: {
printf("输入休眠秒数: ");
if (scanf("%u", &seconds) == 1) {
printf("开始可中断休眠 %u 秒 (按 Ctrl+C 中断)...\n", seconds);
signal(SIGINT, interrupt_handler);
signal(SIGTERM, interrupt_handler);
unsigned int remaining = sleep(seconds);
if (sleep_interrupted || remaining > 0) {
printf("休眠被中断,剩余时间: %u 秒\n", remaining);
} else {
printf("休眠正常完成\n");
}
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
sleep_interrupted = 0;
}
break;
}
case 3:
printf("输入休眠秒数: ");
if (scanf("%u", &seconds) == 1) {
measured_sleep(seconds);
}
break;
case 4: {
printf("输入循环次数: ");
int count;
if (scanf("%d", &count) == 1) {
printf("输入每次休眠秒数: ");
if (scanf("%u", &seconds) == 1) {
printf("开始 %d 次循环休眠,每次 %u 秒...\n", count, seconds);
for (int i = 1; i <= count; i++) {
printf("第 %d 次休眠...\n", i);
sleep(seconds);
printf("第 %d 次休眠完成\n", i);
}
printf("循环休眠完成\n");
}
}
break;
}
case 5:
printf("当前系统时间: ");
fflush(stdout);
system("date");
break;
case 0:
printf("退出睡眠工具\n");
return;
default:
printf("无效选择\n");
break;
}
}
}
int main(int argc, char *argv[]) {
printf("=== 睡眠工具 ===\n");
// 如果有命令行参数,作为工具使用
if (argc > 1) {
return sleep_tool(argc, argv);
}
// 否则启动交互式工具
printf("系统信息:\n");
printf(" PID: %d\n", getpid());
printf(" 页面大小: %ld 字节\n", (long)getpagesize());
char choice;
printf("\n是否启动交互式睡眠工具? (y/N): ");
if (scanf(" %c", &choice) == 1 && (choice == 'y' || choice == 'Y')) {
interactive_sleep_tool();
}
return 0;
}
9. sleep 函数的限制和注意事项 見出しへのリンク
// sleep 函数的重要限制:
// 1. 精度限制
// • 最小精度为 1 秒
// • 实际休眠时间可能比指定时间长
// • 受系统调度和负载影响
// 2. 信号中断
// • 可能被信号中断而提前返回
// • 返回值表示剩余未休眠的时间
// 3. 系统依赖
// • 行为可能因系统而异
// • 某些实时系统可能有不同实现
// 4. 错误处理
// • 很少失败,通常总是成功
// • 返回值主要用于信号中断检测
// 5. 替代方案
// • 需要更高精度时使用 nanosleep
// • 需要可中断等待时使用 select/poll
10. 实际应用场景 見出しへのリンク
场景1:简单的延时控制 見出しへのリンク
void simple_delay() {
printf("执行操作前延时...\n");
sleep(1); // 1秒延时
printf("开始执行操作\n");
}
场景2:轮询间隔控制 見出しへのリンク
void polling_with_interval() {
while (1) {
// 执行检查操作
if (check_condition()) {
break;
}
// 等待一段时间再检查
sleep(5); // 5秒间隔
}
}
场景3:资源重试机制 見出しへのリンク
int retry_with_backoff() {
int max_retries = 5;
int delay = 1;
for (int i = 0; i < max_retries; i++) {
if (attempt_operation()) {
return 1; // 成功
}
printf("操作失败,%d 秒后重试...\n", delay);
sleep(delay);
delay *= 2; // 指数退避
}
return 0; // 最终失败
}
场景4:守护进程心跳 見出しへのリンク
void daemon_heartbeat() {
while (1) {
// 执行守护进程任务
perform_daemon_task();
// 记录心跳日志
log_heartbeat();
// 等待下次心跳
sleep(60); // 1分钟间隔
}
}
11. 性能和最佳实践 見出しへのリンク
// 性能考虑和最佳实践:
// 1. 避免频繁短时间休眠
void bad_example() {
for (int i = 0; i < 1000; i++) {
do_work();
sleep(0); // 不推荐:频繁系统调用
}
}
void good_example() {
for (int i = 0; i < 1000; i++) {
do_work();
}
sleep(1); // 推荐:批量处理后休眠
}
// 2. 处理信号中断
unsigned int safe_sleep(unsigned int seconds) {
unsigned int remaining = seconds;
while (remaining > 0) {
remaining = sleep(remaining);
}
return 0;
}
// 3. 选择合适的休眠函数
void choose_appropriate_function() {
// 需要秒级精度:使用 sleep
sleep(5);
// 需要更高精度:使用 nanosleep
struct timespec ts = {0, 500000000}; // 0.5秒
nanosleep(&ts, NULL);
// 需要可中断等待:使用 select
struct timeval timeout = {1, 0}; // 1秒
select(0, NULL, NULL, NULL, &timeout);
}
12. 系统相关特性 見出しへのリンク
# 查看系统休眠相关配置
cat /proc/sys/kernel/sched_rt_period_us
cat /proc/sys/kernel/sched_rt_runtime_us
# 查看进程定时器信息
cat /proc/self/timers
# 查看系统时钟信息
cat /proc/timer_list
# 测试系统定时器精度
time sleep 1
总结 見出しへのリンク
sleep
是 Linux 系统中最简单易用的延时函数:
关键特性:
- 简单易用: 只需要指定秒数参数
- 系统集成: 与内核调度器紧密集成
- 信号安全: 正确处理信号中断
- 广泛支持: 在所有 Unix-like 系统上可用
主要应用:
- 简单的程序延时控制
- 轮询间隔管理
- 资源访问重试机制
- 守护进程心跳控制
使用要点:
- 理解秒级精度的限制
- 正确处理信号中断返回值
- 根据需求选择合适的休眠函数
- 避免不必要的频繁休眠调用
虽然 sleep
功能简单,但在很多场景下都非常实用,是系统编程的基础工具之一。