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;
}
相关推荐
正在努力的小河2 小时前
Linux设备树简介
linux·运维·服务器
荣光波比2 小时前
Linux(十一)——LVM磁盘配额整理
linux·运维·云计算
LLLLYYYRRRRRTT2 小时前
WordPress (LNMP 架构) 一键部署 Playbook
linux·架构·ansible·mariadb
轻松Ai享生活3 小时前
crash 进程分析流程图
linux
大路谈数字化4 小时前
Centos中内存CPU硬盘的查询
linux·运维·centos
luoqice5 小时前
linux下查看 UDP Server 端口的启用情况
linux
倔强的石头_6 小时前
【Linux指南】动静态库与链接机制:从原理到实践
linux
赏点剩饭7786 小时前
linux中的hostpath卷、nfs卷以及静态持久卷的区别
linux·运维·服务器
神鸟云7 小时前
DELL服务器 R系列 IPMI的配置
linux·运维·服务器·网络·边缘计算·pcdn
herderl7 小时前
**僵尸进程(Zombie Process)** 和**孤儿进程(Orphan Process)**
linux·运维·服务器·网络·网络协议