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 系统中最简单易用的延时函数:

关键特性:

  1. 简单易用: 只需要指定秒数参数
  2. 系统集成: 与内核调度器紧密集成
  3. 信号安全: 正确处理信号中断
  4. 广泛支持: 在所有 Unix-like 系统上可用

主要应用:

  1. 简单的程序延时控制
  2. 轮询间隔管理
  3. 资源访问重试机制
  4. 守护进程心跳控制

使用要点:

  1. 理解秒级精度的限制
  2. 正确处理信号中断返回值
  3. 根据需求选择合适的休眠函数
  4. 避免不必要的频繁休眠调用

虽然 sleep 功能简单,但在很多场景下都非常实用,是系统编程的基础工具之一。