clock_nanosleep系统调用及示例

41. clock_nanosleep - 高精度睡眠

函数介绍

clock_nanosleep系统调用提供纳秒级精度的睡眠功能,支持绝对时间和相对时间两种模式,比传统的nanosleep更加灵活。

函数原型

c 复制代码
#include <time.h>

int clock_nanosleep(clockid_t clock_id, int flags,
                    const struct timespec *request,
                    struct timespec *remain);

功能

使进程睡眠指定的时间,支持高精度纳秒级睡眠。

参数

  • clockid_t clock_id: 时钟ID
  • int flags: 标志位
    • 0: 相对时间睡眠
    • TIMER_ABSTIME: 绝对时间睡眠
  • const struct timespec *request: 请求睡眠的时间
  • struct timespec *remain: 剩余时间(被信号中断时)

返回值

  • 成功时返回0
  • 被信号中断时返回-1,并设置errno为EINTR
  • 失败时返回-1,并设置其他errno

相似函数

  • nanosleep(): 纳秒级睡眠
  • sleep(): 秒级睡眠
  • usleep(): 微秒级睡眠

示例代码

c 复制代码
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>

// 信号处理函数
void signal_handler(int sig) {
    printf("  接收到信号 %d\n", sig);
}

int main() {
    struct timespec request, remain, start, end;
    int result;
    
    printf("=== Clock_nanosleep 函数示例 ===\n");
    
    // 示例1: 相对时间睡眠
    printf("\n示例1: 相对时间睡眠\n");
    
    // 睡眠100毫秒
    request.tv_sec = 0;
    request.tv_nsec = 100000000; // 100毫秒 = 100,000,000纳秒
    
    if (clock_gettime(CLOCK_MONOTONIC, &start) == -1) {
        perror("  获取开始时间失败");
    }
    
    printf("  开始睡眠: %ld.%09ld 秒\n", start.tv_sec, start.tv_nsec);
    result = clock_nanosleep(CLOCK_MONOTONIC, 0, &request, NULL);
    
    if (result == -1) {
        if (errno == EINTR) {
            printf("  睡眠被信号中断\n");
        } else {
            printf("  睡眠失败: %s\n", strerror(errno));
        }
    } else {
        printf("  睡眠完成\n");
        if (clock_gettime(CLOCK_MONOTONIC, &end) == -1) {
            perror("  获取结束时间失败");
        } else {
            long long actual_sleep = (end.tv_sec - start.tv_sec) * 1000000000LL + 
                                   (end.tv_nsec - start.tv_nsec);
            printf("  实际睡眠时间: %lld 纳秒\n", actual_sleep);
        }
    }
    
    // 示例2: 绝对时间睡眠
    printf("\n示例2: 绝对时间睡眠\n");
    
    // 获取当前时间
    if (clock_gettime(CLOCK_REALTIME, &start) == 0) {
        printf("  当前时间: %ld.%09ld 秒\n", start.tv_sec, start.tv_nsec);
        
        // 设置绝对睡眠时间(当前时间+2秒)
        struct timespec absolute_time;
        absolute_time.tv_sec = start.tv_sec + 2;
        absolute_time.tv_nsec = start.tv_nsec;
        
        printf("  绝对睡眠时间: %ld.%09ld 秒\n", absolute_time.tv_sec, absolute_time.tv_nsec);
        
        result = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &absolute_time, NULL);
        if (result == -1) {
            if (errno == EINTR) {
                printf("  绝对时间睡眠被信号中断\n");
            } else {
                printf("  绝对时间睡眠失败: %s\n", strerror(errno));
            }
        } else {
            printf("  绝对时间睡眠完成\n");
        }
    }
    
    // 示例3: 被信号中断的睡眠
    printf("\n示例3: 被信号中断的睡眠\n");
    
    // 设置信号处理
    signal(SIGUSR1, signal_handler);
    
    // 启动另一个线程发送信号
    pid_t pid = fork();
    if (pid == 0) {
        // 子进程:延迟发送信号
        sleep(1);
        kill(getppid(), SIGUSR1);
        exit(0);
    } else if (pid > 0) {
        // 父进程:长时间睡眠
        request.tv_sec = 5;
        request.tv_nsec = 0;
        
        printf("  开始5秒睡眠,1秒后会被信号中断\n");
        result = clock_nanosleep(CLOCK_MONOTONIC, 0, &request, &remain);
        
        if (result == -1 && errno == EINTR) {
            printf("  睡眠被信号中断\n");
            printf("  剩余时间: %ld.%09ld 秒\n", remain.tv_sec, remain.tv_nsec);
        }
        
        wait(NULL); // 等待子进程结束
    }
    
    // 示例4: 错误处理演示
    printf("\n示例4: 错误处理演示\n");
    
    // 使用无效的时钟ID
    request.tv_sec = 1;
    request.tv_nsec = 0;
    result = clock_nanosleep(999, 0, &request, NULL);
    if (result == -1) {
        if (errno == EINVAL) {
            printf("  无效时钟ID错误处理正确: %s\n", strerror(errno));
        }
    }
    
    // 使用无效的时间值
    request.tv_sec = -1;
    request.tv_nsec = 0;
    result = clock_nanosleep(CLOCK_MONOTONIC, 0, &request, NULL);
    if (result == -1) {
        if (errno == EINVAL) {
            printf("  无效时间值错误处理正确: %s\n", strerror(errno));
        }
    }
    
    // 使用过大的纳秒值
    request.tv_sec = 0;
    request.tv_nsec = 1000000000; // 10亿纳秒 = 1秒,但应该 < 1秒
    result = clock_nanosleep(CLOCK_MONOTONIC, 0, &request, NULL);
    if (result == -1) {
        if (errno == EINVAL) {
            printf("  纳秒值过大错误处理正确: %s\n", strerror(errno));
        }
    }
    
    // 示例5: 不同时钟的睡眠效果
    printf("\n示例5: 不同时钟的睡眠效果\n");
    
    printf("CLOCK_REALTIME睡眠:\n");
    printf("  - 基于系统实时时间\n");
    printf("  - 受系统时间调整影响\n");
    printf("  - 适用于绝对时间睡眠\n\n");
    
    printf("CLOCK_MONOTONIC睡眠:\n");
    printf("  - 基于单调递增时间\n");
    printf("  - 不受系统时间调整影响\n");
    printf("  - 适用于相对时间睡眠\n\n");
    
    // 示例6: 高精度定时器演示
    printf("示例6: 高精度定时器演示\n");
    
    printf("创建100毫秒间隔的定时器循环:\n");
    struct timespec interval;
    interval.tv_sec = 0;
    interval.tv_nsec = 100000000; // 100毫秒
    
    for (int i = 0; i < 5; i++) {
        if (clock_gettime(CLOCK_MONOTONIC, &start) == 0) {
            printf("  第%d次: 时间 %ld.%09ld\n", i+1, start.tv_sec, start.tv_nsec);
        }
        
        result = clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, NULL);
        if (result == -1) {
            if (errno == EINTR) {
                printf("  第%d次: 睡眠被中断\n", i+1);
                break;
            }
        }
    }
    
    // 示例7: 睡眠精度测试
    printf("\n示例7: 睡眠精度测试\n");
    
    struct timespec sleep_times[] = {
        {0, 1000},      // 1微秒
        {0, 10000},     // 10微秒
        {0, 100000},    // 100微秒
        {0, 1000000},   // 1毫秒
        {0, 10000000},  // 10毫秒
        {0, 100000000}, // 100毫秒
        {1, 0}          // 1秒
    };
    
    const char *time_labels[] = {
        "1微秒", "10微秒", "100微秒", "1毫秒", "10毫秒", "100毫秒", "1秒"
    };
    
    printf("睡眠精度测试结果:\n");
    for (int i = 0; i < 7; i++) {
        if (clock_gettime(CLOCK_MONOTONIC, &start) == 0) {
            result = clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep_times[i], NULL);
            if (clock_gettime(CLOCK_MONOTONIC, &end) == 0) {
                long long actual = (end.tv_sec - start.tv_sec) * 1000000000LL + 
                                 (end.tv_nsec - start.tv_nsec);
                long long requested = sleep_times[i].tv_sec * 1000000000LL + 
                                    sleep_times[i].tv_nsec;
                long long diff = actual - requested;
                
                printf("  %-8s: 请求%8lld ns, 实际%8lld ns, 误差%+6lld ns\n",
                       time_labels[i], requested, actual, diff);
            }
        }
    }
    
    // 示例8: 实际应用场景
    printf("\n示例8: 实际应用场景\n");
    
    // 场景1: 实时系统定时
    printf("场景1: 实时系统定时\n");
    printf("在实时应用中确保精确的时间间隔\n");
    
    // 场景2: 性能基准测试
    printf("\n场景2: 性能基准测试\n");
    printf("提供精确的延迟控制用于性能测试\n");
    
    // 场景3: 动画和游戏循环
    printf("\n场景3: 动画和游戏循环\n");
    printf("维持稳定的帧率和更新频率\n");
    
    // 场景4: 网络超时控制
    printf("\n场景4: 网络超时控制\n");
    printf("实现精确的网络操作超时机制\n");
    
    printf("\n总结:\n");
    printf("clock_nanosleep提供纳秒级精度的睡眠功能\n");
    printf("支持相对时间和绝对时间两种模式\n");
    printf("比传统sleep函数更加灵活和精确\n");
    printf("正确处理信号中断和剩余时间计算\n");
    printf("适用于需要高精度时间控制的应用场景\n");
    
    return 0;
}

42. clock_settime - 设置时钟时间

函数介绍

clock_settime系统调用用于设置指定时钟的时间值。它允许程序修改系统时钟,主要用于时间同步和系统管理。

函数原型

c 复制代码
#include <time.h>

int clock_settime(clockid_t clk_id, const struct timespec *tp);

功能

设置指定时钟的时间值。

参数

  • clockid_t clk_id: 时钟ID(通常为CLOCK_REALTIME)
  • const struct timespec *tp: 指向timespec结构体的指针,包含新的时间值

返回值

  • 成功时返回0
  • 失败时返回-1,并设置errno

特殊限制

  • 需要CAP_SYS_TIME能力或root权限
  • 通常只能设置CLOCK_REALTIME时钟

相似函数

  • settimeofday(): 设置系统时间
  • stime(): 设置系统时间(已废弃)

示例代码

c 复制代码
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>

int main() {
    struct timespec current_time, new_time;
    int result;
    
    printf("=== Clock_settime 函数示例 ===\n");
    printf("当前用户 UID: %d\n", getuid());
    printf("当前有效 UID: %d\n", geteuid());
    
    // 示例1: 获取当前时间
    printf("\n示例1: 获取当前时间\n");
    
    if (clock_gettime(CLOCK_REALTIME, &current_time) == -1) {
        perror("  获取当前时间失败");
    } else {
        printf("  当前系统时间: %ld.%09ld 秒\n", current_time.tv_sec, current_time.tv_nsec);
        printf("  对应日期: %s", ctime(&current_time.tv_sec));
    }
    
    // 示例2: 权限检查
    printf("\n示例2: 权限检查\n");
    
    // 尝试设置时间(通常会失败)
    new_time.tv_sec = current_time.tv_sec;
    new_time.tv_nsec = current_time.tv_nsec;
    
    result = clock_settime(CLOCK_REALTIME, &new_time);
    if (result == -1) {
        if (errno == EPERM) {
            printf("  权限不足设置时间: %s\n", strerror(errno));
            printf("  说明: 需要CAP_SYS_TIME能力或root权限\n");
        } else {
            printf("  设置时间失败: %s\n", strerror(errno));
        }
    } else {
        printf("  时间设置成功\n");
    }
    
    // 示例3: 错误处理演示
    printf("\n示例3: 错误处理演示\n");
    
    // 使用无效的时钟ID
    result = clock_settime(999, &new_time);
    if (result == -1) {
        if (errno == EINVAL) {
            printf("  无效时钟ID错误处理正确: %s\n", strerror(errno));
        }
    }
    
    // 使用无效的时间值
    struct timespec invalid_time;
    invalid_time.tv_sec = -1;
    invalid_time.tv_nsec = 0;
    
    result = clock_settime(CLOCK_REALTIME, &invalid_time);
    if (result == -1) {
        if (errno == EINVAL) {
            printf("  无效时间值错误处理正确: %s\n", strerror(errno));
        }
    }
    
    // 使用过大的纳秒值
    invalid_time.tv_sec = current_time.tv_sec;
    invalid_time.tv_nsec = 1000000000; // 10亿纳秒,应该 < 1秒
    
    result = clock_settime(CLOCK_REALTIME, &invalid_time);
    if (result == -1) {
        if (errno == EINVAL) {
            printf("  纳秒值过大错误处理正确: %s\n", strerror(errno));
        }
    }
    
    // 使用NULL指针
    result = clock_settime(CLOCK_REALTIME, NULL);
    if (result == -1) {
        if (errno == EFAULT) {
            printf("  NULL指针错误处理正确: %s\n", strerror(errno));
        }
    }
    
    // 示例4: 支持的时钟类型
    printf("\n示例4: 支持的时钟类型\n");
    
    printf("CLOCK_REALTIME:\n");
    printf("  - 系统实时钟\n");
    printf("  - 可以被设置\n");
    printf("  - 用于表示当前时间\n\n");
    
    printf("其他时钟类型:\n");
    printf("  - CLOCK_MONOTONIC: 通常不能设置\n");
    printf("  - CLOCK_PROCESS_CPUTIME_ID: 不能设置\n");
    printf("  - CLOCK_THREAD_CPUTIME_ID: 不能设置\n\n");
    
    // 示例5: 时间格式转换
    printf("示例5: 时间格式转换\n");
    
    if (clock_gettime(CLOCK_REALTIME, &current_time) == 0) {
        printf("  当前时间: %ld.%09ld 秒\n", current_time.tv_sec, current_time.tv_nsec);
        
        // 从日期字符串转换为time_t
        struct tm time_info;
        strptime("2024-01-01 12:00:00", "%Y-%m-%d %H:%M:%S", &time_info);
        time_t new_time_t = mktime(&time_info);
        
        printf("  转换时间: %s", ctime(&new_time_t));
        
        // 转换为timespec格式
        struct timespec converted_time;
        converted_time.tv_sec = new_time_t;
        converted_time.tv_nsec = 0;
        
        printf("  timespec格式: %ld.%09ld 秒\n", converted_time.tv_sec, converted_time.tv_nsec);
    }
    
    // 示例6: 时区考虑
    printf("\n示例6: 时区考虑\n");
    
    if (clock_gettime(CLOCK_REALTIME, &current_time) == 0) {
        printf("  UTC时间: %ld.%09ld 秒\n", current_time.tv_sec, current_time.tv_nsec);
        
        // 获取本地时区偏移
        struct tm *utc_tm = gmtime(&current_time.tv_sec);
        struct tm *local_tm = localtime(&current_time.tv_sec);
        
        time_t utc_time = mktime(utc_tm);
        time_t local_time = mktime(local_tm);
        
        long tz_offset = local_time - utc_time;
        printf("  时区偏移: %+ld 秒\n", tz_offset);
    }
    
    // 示例7: 安全考虑
    printf("\n示例7: 安全考虑\n");
    printf("使用clock_settime的安全注意事项:\n");
    printf("1. 需要适当的权限(CAP_SYS_TIME或root)\n");
    printf("2. 不当的时间设置可能影响系统稳定性\n");
    printf("3. 时间跳跃可能影响依赖时间的应用程序\n");
    printf("4. 应该使用NTP等标准时间同步服务\n");
    printf("5. 在生产环境中谨慎使用\n\n");
    
    // 示例8: 实际应用场景
    printf("示例8: 实际应用场景\n");
    
    // 场景1: NTP客户端
    printf("场景1: NTP客户端\n");
    printf("  - 从NTP服务器获取时间\n");
    printf("  - 调整系统时钟\n");
    printf("  - 保持时间同步\n\n");
    
    // 场景2: 系统初始化
    printf("场景2: 系统初始化\n");
    printf("  - 设置初始系统时间\n");
    printf("  - 从硬件时钟同步\n");
    printf("  - 恢复时间设置\n\n");
    
    // 场景3: 调试和测试
    printf("场景3: 调试和测试\n");
    printf("  - 设置特定时间进行测试\n");
    printf("  - 模拟时间相关场景\n");
    printf("  - 性能基准测试\n\n");
    
    // 场景4: 时间同步服务
    printf("场景4: 时间同步服务\n");
    printf("  - 分布式系统时间协调\n");
    printf("  - 数据库事务时间戳\n");
    printf("  - 日志时间同步\n\n");
    
    // 示例9: 替代方案
    printf("示例9: 替代方案\n");
    printf("现代时间管理推荐使用:\n");
    printf("1. NTP守护进程(ntpd)\n");
    printf("2. systemd-timesyncd\n");
    printf("3. chrony\n");
    printf("4. chronyd\n");
    printf("5. 避免手动设置系统时间\n\n");
    
    printf("总结:\n");
    printf("clock_settime用于设置系统时钟时间\n");
    printf("需要适当的权限才能使用\n");
    printf("主要用于时间同步服务\n");
    printf("不当使用可能影响系统稳定性\n");
    printf("推荐使用标准的时间同步服务\n");
    
    return 0;
}
相关推荐
Jie_1725 分钟前
【linux】高可用集群Keepalived
linux·运维·服务器
aiprtem31 分钟前
LVGL + ESP-Brookesia 嵌入式模拟桌面应用开发
linux·c语言·物联网
xx.ii2 小时前
4.Linux 应用程序的安装和管理
linux·服务器·网络
奋斗的蛋黄3 小时前
解析分区、挂载与块设备:Linux 存储管理核心命令详解
linux·服务器·网络
墨迹的陌离3 小时前
【Linux】重生之从零开始学习运维之Mysql
linux·运维·服务器·数据库·学习·mysql
Ray Song4 小时前
Linux DNS解析1--终端通过网关或者路由器进行域名解析的原理
linux·运维·服务器·dns解析
Zero .4 小时前
macbook安装homebrew
linux·运维·服务器
NEXU54 小时前
Linux:线程同步与线程互斥
linux
FJW0208144 小时前
负载均衡集群HAproxy
linux·服务器·云原生·负载均衡
云道轩4 小时前
使用Docker在Rocky Linux 9.5上在线部署LangFlow
linux·人工智能·docker·容器·langflow