clock_adjtime – 调整时钟参数
函数介绍
clock_adjtime
系统调用用于调整指定时钟的参数,主要用于精密时间同步。它可以设置时钟的频率调整、时间偏移等参数,常用于NTP客户端实现。
函数原型
#include <time.h>
#include <sys/timex.h>
#include <sys/syscall.h>
#include <unistd.h>
int clock_adjtime(clockid_t clk_id, struct timex *buf);
功能
调整指定时钟的参数,包括频率、时间偏移等,用于精密时间同步。
参数
clockid_t clk_id
: 时钟IDCLOCK_REALTIME
: 系统实时钟CLOCK_TAI
: 国际原子时
struct timex *buf
: 指向timex结构体的指针,包含调整参数
返回值
- 成功时返回状态码
- 失败时返回-1,并设置errno
特殊限制
- 需要CAP_SYS_TIME能力
- 通常需要root权限
相似函数
adjtimex()
: 调整系统时钟settimeofday()
: 设置系统时间
示例代码
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <sys/timex.h>
#include <time.h>
#include <errno.h>
#include <string.h>
// 系统调用包装
static int clock_adjtime_wrapper(clockid_t clk_id, struct timex *buf) {
return syscall(__NR_clock_adjtime, clk_id, buf);
}
int main() {
struct timex tx;
int result;
printf("=== Clock_adjtime 函数示例 ===\n");
printf("当前用户 UID: %d\n", getuid());
printf("当前有效 UID: %d\n", geteuid());
// 示例1: 获取当前时钟状态
printf("\n示例1: 获取时钟状态\n");
memset(&tx, 0, sizeof(tx));
tx.modes = 0; // 仅查询状态
result = clock_adjtime_wrapper(CLOCK_REALTIME, &tx);
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");
printf(" 状态码: %d\n", result);
printf(" 频率偏移: %ld\n", tx.freq);
printf(" 最大误差: %ld\n", tx.maxerror);
printf(" 估计误差: %ld\n", tx.esterror);
}
// 示例2: 查询时钟参数(不修改)
printf("\n示例2: 查询时钟参数\n");
memset(&tx, 0, sizeof(tx));
tx.modes = 0;
result = clock_adjtime_wrapper(CLOCK_REALTIME, &tx);
if (result != -1) {
printf(" 时钟参数:\n");
printf(" 状态: %d\n", tx.status);
printf(" 频率偏移: %ld ppm\n", tx.freq / 65536); // 转换为ppm
printf(" 时间常数: %ld\n", tx.constant);
printf(" 精度: %ld ns\n", tx.precision);
printf(" 容差: %ld ppm\n", tx.tolerance / 65536); // 转换为ppm
}
// 示例3: 错误处理演示
printf("\n示例3: 错误处理演示\n");
// 使用无效的时钟ID
memset(&tx, 0, sizeof(tx));
result = clock_adjtime_wrapper(999, &tx);
if (result == -1) {
if (errno == EINVAL) {
printf(" 无效时钟ID错误处理正确: %s\n", strerror(errno));
}
}
// 使用无效的指针
result = clock_adjtime_wrapper(CLOCK_REALTIME, NULL);
if (result == -1) {
if (errno == EFAULT) {
printf(" 无效指针错误处理正确: %s\n", strerror(errno));
}
}
// 示例4: 时钟类型说明
printf("\n示例4: 支持的时钟类型\n");
printf("CLOCK_REALTIME: 系统实时钟(wall-clock time)\n");
printf(" - 可以被手动设置\n");
printf(" - 受NTP调整影响\n");
printf(" - 用于日常时间表示\n\n");
printf("CLOCK_TAI: 国际原子时\n");
printf(" - 连续时间,无闰秒\n");
printf(" - 与时钟实时相差固定偏移\n");
printf(" - 用于精密时间计算\n\n");
// 示例5: NTP相关参数说明
printf("示例5: NTP相关参数说明\n");
printf("timex结构体重要字段:\n");
printf(" modes: 指定要设置的参数\n");
printf(" offset: 时间偏移(纳秒)\n");
printf(" freq: 频率偏移(scaled ppm)\n");
printf(" maxerror: 最大误差估计\n");
printf(" esterror: 误差估计\n");
printf(" status: 时钟状态标志\n");
printf(" constant: PLL时间常数\n");
printf(" precision: 时钟精度\n");
printf(" tolerance: 频率容差\n\n");
// 示例6: 权限和安全考虑
printf("示例6: 权限和安全考虑\n");
printf("使用clock_adjtime需要:\n");
printf("1. CAP_SYS_TIME能力\n");
printf("2. 或者root权限\n");
printf("3. 某些操作可能需要额外权限\n\n");
printf("安全注意事项:\n");
printf("1. 不当的时间调整可能影响系统稳定性\n");
printf("2. 频率调整过大可能导致时间跳跃\n");
printf("3. 应谨慎设置时间参数\n");
printf("4. 建议使用NTP守护进程进行时间同步\n\n");
// 示例7: 实际应用场景
printf("示例7: 实际应用场景\n");
printf("clock_adjtime主要用于:\n");
printf("1. NTP客户端实现\n");
printf("2. 精密时间同步服务\n");
printf("3. 科学计算时间校准\n");
printf("4. 金融系统时间同步\n");
printf("5. 分布式系统时间协调\n\n");
printf("典型使用流程:\n");
printf("1. 查询当前时钟状态\n");
printf("2. 计算需要的调整参数\n");
printf("3. 应用调整参数\n");
printf("4. 监控调整效果\n");
printf("5. 必要时进行微调\n\n");
printf("总结:\n");
printf("clock_adjtime是用于精密时钟调整的系统调用\n");
printf("主要用于NTP客户端和时间同步服务\n");
printf("需要适当的权限才能使用\n");
printf("不当使用可能导致系统时间异常\n");
return 0;
}
clock_getres – 获取时钟精度
函数介绍
clock_getres
系统调用用于获取指定时钟的精度(分辨率)。它返回时钟能够表示的最小时间间隔。
函数原型
#include <time.h>
int clock_getres(clockid_t clk_id, struct timespec *res);
功能
获取指定时钟的精度,即能够表示的最小时间间隔。
参数
clockid_t clk_id
: 时钟IDstruct timespec *res
: 指向timespec结构体的指针,用于存储精度信息
返回值
- 成功时返回0
- 失败时返回-1,并设置errno
特似函数
clock_gettime()
: 获取时钟时间gettimeofday()
: 获取系统时间
示例代码
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <string.h>
int main() {
struct timespec res;
int result;
printf("=== Clock_getres 函数示例 ===\n");
// 示例1: 获取各种时钟的精度
printf("\n示例1: 不同时钟的精度\n");
// CLOCK_REALTIME
result = clock_getres(CLOCK_REALTIME, &res);
if (result == -1) {
printf(" CLOCK_REALTIME精度获取失败: %s\n", strerror(errno));
} else {
printf(" CLOCK_REALTIME精度: %ld.%09ld 秒\n", res.tv_sec, res.tv_nsec);
printf(" 即: %ld 纳秒\n", res.tv_nsec);
}
// CLOCK_MONOTONIC
result = clock_getres(CLOCK_MONOTONIC, &res);
if (result == -1) {
printf(" CLOCK_MONOTONIC精度获取失败: %s\n", strerror(errno));
} else {
printf(" CLOCK_MONOTONIC精度: %ld.%09ld 秒\n", res.tv_sec, res.tv_nsec);
printf(" 即: %ld 纳秒\n", res.tv_nsec);
}
// CLOCK_PROCESS_CPUTIME_ID
result = clock_getres(CLOCK_PROCESS_CPUTIME_ID, &res);
if (result == -1) {
printf(" CLOCK_PROCESS_CPUTIME_ID精度获取失败: %s\n", strerror(errno));
} else {
printf(" CLOCK_PROCESS_CPUTIME_ID精度: %ld.%09ld 秒\n", res.tv_sec, res.tv_nsec);
printf(" 即: %ld 纳秒\n", res.tv_nsec);
}
// CLOCK_THREAD_CPUTIME_ID
result = clock_getres(CLOCK_THREAD_CPUTIME_ID, &res);
if (result == -1) {
printf(" CLOCK_THREAD_CPUTIME_ID精度获取失败: %s\n", strerror(errno));
} else {
printf(" CLOCK_THREAD_CPUTIME_ID精度: %ld.%09ld 秒\n", res.tv_sec, res.tv_nsec);
printf(" 即: %ld 纳秒\n", res.tv_nsec);
}
// 示例2: 错误处理演示
printf("\n示例2: 错误处理演示\n");
// 使用无效的时钟ID
result = clock_getres(999, &res);
if (result == -1) {
if (errno == EINVAL) {
printf(" 无效时钟ID错误处理正确: %s\n", strerror(errno));
}
}
// 使用NULL指针
result = clock_getres(CLOCK_REALTIME, NULL);
if (result == 0) {
printf(" NULL指针参数被接受(用于查询时钟是否存在)\n");
}
// 示例3: 时钟类型说明
printf("\n示例3: 支持的时钟类型\n");
printf("CLOCK_REALTIME: 系统实时钟\n");
printf(" - 可以被设置和调整\n");
printf(" - 受NTP和手动调整影响\n");
printf(" - 用于获取当前时间\n\n");
printf("CLOCK_MONOTONIC: 单调时钟\n");
printf(" - 不会倒退\n");
printf(" - 不受系统时间调整影响\n");
printf(" - 用于测量时间间隔\n\n");
printf("CLOCK_PROCESS_CPUTIME_ID: 进程CPU时间\n");
printf(" - 测量进程使用的CPU时间\n");
printf(" - 通常有较高精度\n\n");
printf("CLOCK_THREAD_CPUTIME_ID: 线程CPU时间\n");
printf(" - 测量线程使用的CPU时间\n");
printf(" - 用于性能分析\n\n");
// 示例4: 精度对比
printf("示例4: 不同时钟精度对比\n");
clockid_t clocks[] = {
CLOCK_REALTIME,
CLOCK_MONOTONIC,
CLOCK_PROCESS_CPUTIME_ID,
CLOCK_THREAD_CPUTIME_ID
};
const char *clock_names[] = {
"CLOCK_REALTIME",
"CLOCK_MONOTONIC",
"CLOCK_PROCESS_CPUTIME_ID",
"CLOCK_THREAD_CPUTIME_ID"
};
for (int i = 0; i < 4; i++) {
if (clock_getres(clocks[i], &res) == 0) {
printf(" %-25s: %10ld ns\n", clock_names[i], res.tv_nsec);
}
}
// 示例5: 实际应用演示
printf("\n示例5: 实际应用演示\n");
printf("时钟精度对程序设计的影响:\n");
// 演示高精度计时
struct timespec start, end, diff;
if (clock_getres(CLOCK_MONOTONIC, &res) == 0) {
printf(" 使用CLOCK_MONOTONIC进行高精度计时:\n");
printf(" 理论精度: %ld 纳秒\n", res.tv_nsec);
// 进行简单计时演示
if (clock_gettime(CLOCK_MONOTONIC, &start) == 0) {
// 执行一些操作
volatile int sum = 0;
for (int i = 0; i < 1000; i++) {
sum += i;
}
if (clock_gettime(CLOCK_MONOTONIC, &end) == 0) {
// 计算时间差
if (end.tv_nsec < start.tv_nsec) {
diff.tv_sec = end.tv_sec - start.tv_sec - 1;
diff.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
} else {
diff.tv_sec = end.tv_sec - start.tv_sec;
diff.tv_nsec = end.tv_nsec - start.tv_nsec;
}
printf(" 实际测量时间: %ld.%09ld 秒\n", diff.tv_sec, diff.tv_nsec);
}
}
}
// 示例6: 性能考虑
printf("\n示例6: 性能考虑\n");
printf("不同精度时钟的性能特点:\n");
printf("1. 高精度时钟通常开销较大\n");
printf("2. 需要在精度和性能间平衡\n");
printf("3. 选择合适的时钟类型很重要\n");
printf("4. 避免不必要的高精度要求\n\n");
printf("时钟选择建议:\n");
printf("- 一般计时: CLOCK_REALTIME\n");
printf("- 性能测量: CLOCK_MONOTONIC\n");
printf("- CPU使用率: CLOCK_PROCESS_CPUTIME_ID\n");
printf("- 线程性能: CLOCK_THREAD_CPUTIME_ID\n\n");
printf("总结:\n");
printf("clock_getres用于查询时钟精度\n");
printf("不同类型的时钟有不同的精度\n");
printf("了解时钟精度有助于正确使用计时函数\n");
printf("合理选择时钟类型可以提高程序性能\n");
return 0;
}
clock_gettime – 获取时钟时间
函数介绍
clock_gettime
系统调用用于获取指定时钟的当前时间。它比传统的gettimeofday
提供了更高的精度和更多的时钟类型选择。
函数原型
#include <time.h>
int clock_gettime(clockid_t clk_id, struct timespec *tp);
功能
获取指定时钟的当前时间值。
参数
clockid_t clk_id
: 时钟IDstruct timespec *tp
: 指向timespec结构体的指针,用于存储时间信息
返回值
- 成功时返回0
- 失败时返回-1,并设置errno
相似函数
gettimeofday()
: 获取系统时间time()
: 获取秒级时间clock_getres()
: 获取时钟精度
示例代码
#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 ts;
int result;
printf("=== Clock_gettime 函数示例 ===\n");
// 示例1: 获取各种时钟的时间
printf("\n示例1: 不同时钟的时间\n");
// CLOCK_REALTIME
result = clock_gettime(CLOCK_REALTIME, &ts);
if (result == -1) {
printf(" CLOCK_REALTIME时间获取失败: %s\n", strerror(errno));
} else {
printf(" CLOCK_REALTIME时间: %ld.%09ld 秒\n", ts.tv_sec, ts.tv_nsec);
printf(" 对应日期: %s", ctime(&ts.tv_sec));
}
// CLOCK_MONOTONIC
result = clock_gettime(CLOCK_MONOTONIC, &ts);
if (result == -1) {
printf(" CLOCK_MONOTONIC时间获取失败: %s\n", strerror(errno));
} else {
printf(" CLOCK_MONOTONIC时间: %ld.%09ld 秒\n", ts.tv_sec, ts.tv_nsec);
}
// CLOCK_PROCESS_CPUTIME_ID
result = clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts);
if (result == -1) {
printf(" CLOCK_PROCESS_CPUTIME_ID时间获取失败: %s\n", strerror(errno));
} else {
printf(" 进程CPU时间: %ld.%09ld 秒\n", ts.tv_sec, ts.tv_nsec);
}
// CLOCK_THREAD_CPUTIME_ID
result = clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ts);
if (result == -1) {
printf(" CLOCK_THREAD_CPUTIME_ID时间获取失败: %s\n", strerror(errno));
} else {
printf(" 线程CPU时间: %ld.%09ld 秒\n", ts.tv_sec, ts.tv_nsec);
}
// 示例2: 高精度计时演示
printf("\n示例2: 高精度计时演示\n");
struct timespec start, end, elapsed;
// 使用CLOCK_MONOTONIC进行计时
if (clock_gettime(CLOCK_MONOTONIC, &start) == -1) {
perror(" 获取开始时间失败");
} else {
printf(" 开始时间: %ld.%09ld 秒\n", start.tv_sec, start.tv_nsec);
// 执行一些操作
printf(" 执行计算操作...\n");
volatile long sum = 0;
for (long i = 0; i < 1000000; i++) {
sum += i;
}
if (clock_gettime(CLOCK_MONOTONIC, &end) == -1) {
perror(" 获取结束时间失败");
} else {
printf(" 结束时间: %ld.%09ld 秒\n", end.tv_sec, end.tv_nsec);
// 计算耗时
if (end.tv_nsec < start.tv_nsec) {
elapsed.tv_sec = end.tv_sec - start.tv_sec - 1;
elapsed.tv_nsec = 1000000000 + end.tv_nsec - start.tv_nsec;
} else {
elapsed.tv_sec = end.tv_sec - start.tv_sec;
elapsed.tv_nsec = end.tv_nsec - start.tv_nsec;
}
printf(" 计算耗时: %ld.%09ld 秒\n", elapsed.tv_sec, elapsed.tv_nsec);
printf(" 即: %ld 纳秒\n", elapsed.tv_sec * 1000000000 + elapsed.tv_nsec);
}
}
// 示例3: 错误处理演示
printf("\n示例3: 错误处理演示\n");
// 使用无效的时钟ID
result = clock_gettime(999, &ts);
if (result == -1) {
if (errno == EINVAL) {
printf(" 无效时钟ID错误处理正确: %s\n", strerror(errno));
}
}
// 使用NULL指针
result = clock_gettime(CLOCK_REALTIME, NULL);
if (result == -1) {
if (errno == EFAULT) {
printf(" NULL指针错误处理正确: %s\n", strerror(errno));
}
}
// 示例4: 时间格式转换
printf("\n示例4: 时间格式转换\n");
if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
printf(" 原始时间: %ld.%09ld 秒\n", ts.tv_sec, ts.tv_nsec);
// 转换为毫秒
long milliseconds = ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
printf(" 毫秒表示: %ld ms\n", milliseconds);
// 转换为微秒
long microseconds = ts.tv_sec * 1000000 + ts.tv_nsec / 1000;
printf(" 微秒表示: %ld μs\n", microseconds);
// 转换为纳秒
long long nanoseconds = (long long)ts.tv_sec * 1000000000 + ts.tv_nsec;
printf(" 纳秒表示: %lld ns\n", nanoseconds);
}
// 示例5: 不同时钟的特性对比
printf("\n示例5: 不同时钟特性对比\n");
printf("CLOCK_REALTIME特性:\n");
printf(" - 表示实际时间(墙上时钟)\n");
printf(" - 可以被系统管理员修改\n");
printf(" - 受NTP同步影响\n");
printf(" - 适用于获取当前日期时间\n\n");
printf("CLOCK_MONOTONIC特性:\n");
printf(" - 单调递增,不会倒退\n");
printf(" - 不受系统时间调整影响\n");
printf(" - 适用于测量时间间隔\n");
printf(" - 进程启动时通常为0\n\n");
printf("CLOCK_PROCESS_CPUTIME_ID特性:\n");
printf(" - 测量进程使用的CPU时间\n");
printf(" - 包括所有线程的CPU时间\n");
printf(" - 不包括睡眠时间\n");
printf(" - 适用于性能分析\n\n");
printf("CLOCK_THREAD_CPUTIME_ID特性:\n");
printf(" - 测量当前线程使用的CPU时间\n");
printf(" - 不包括睡眠时间\n");
printf(" - 适用于线程性能分析\n\n");
// 示例6: 实际应用场景
printf("示例6: 实际应用场景\n");
// 场景1: 性能基准测试
printf("场景1: 性能基准测试\n");
if (clock_gettime(CLOCK_MONOTONIC, &start) == 0) {
// 模拟算法执行
volatile int dummy = 0;
for (int i = 0; i < 1000000; i++) {
dummy += i * i;
}
if (clock_gettime(CLOCK_MONOTONIC, &end) == 0) {
long long duration = (end.tv_sec - start.tv_sec) * 1000000000LL +
(end.tv_nsec - start.tv_nsec);
printf(" 算法执行时间: %lld 纳秒\n", duration);
}
}
// 场景2: 超时控制
printf("\n场景2: 超时控制\n");
if (clock_gettime(CLOCK_MONOTONIC, &start) == 0) {
long timeout_ns = 5000000000LL; // 5秒超时
// 模拟等待操作
while (1) {
if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0) {
long long elapsed = (ts.tv_sec - start.tv_sec) * 1000000000LL +
(ts.tv_nsec - start.tv_nsec);
if (elapsed >= timeout_ns) {
printf(" 操作超时(5秒)\n");
break;
}
}
usleep(100000); // 休眠100ms
}
}
// 场景3: CPU使用率监控
printf("\n场景3: CPU使用率监控\n");
struct timespec cpu_start, cpu_end;
struct timespec wall_start, wall_end;
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &cpu_start) == 0 &&
clock_gettime(CLOCK_MONOTONIC, &wall_start) == 0) {
// 执行一些CPU密集型操作
volatile double result = 1.0;
for (int i = 0; i < 1000000; i++) {
result *= 1.000001;
}
if (clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &cpu_end) == 0 &&
clock_gettime(CLOCK_MONOTONIC, &wall_end) == 0) {
long long cpu_time = (cpu_end.tv_sec - cpu_start.tv_sec) * 1000000000LL +
(cpu_end.tv_nsec - cpu_start.tv_nsec);
long long wall_time = (wall_end.tv_sec - wall_start.tv_sec) * 1000000000LL +
(wall_end.tv_nsec - wall_start.tv_nsec);
double cpu_usage = (double)cpu_time / wall_time * 100;
printf(" CPU使用率: %.2f%%\n", cpu_usage);
printf(" CPU时间: %lld 纳秒\n", cpu_time);
printf(" 墙钟时间: %lld 纳秒\n", wall_time);
}
}
// 示例7: 时区和本地时间
printf("\n示例7: 时区和本地时间\n");
if (clock_gettime(CLOCK_REALTIME, &ts) == 0) {
printf(" UTC时间: %ld.%09ld\n", ts.tv_sec, ts.tv_nsec);
// 转换为本地时间
struct tm *local_tm = localtime(&ts.tv_sec);
if (local_tm) {
char time_str[100];
strftime(time_str, sizeof(time_str), "%Y-%m-%d %H:%M:%S", local_tm);
printf(" 本地时间: %s.%09ld\n", time_str, ts.tv_nsec);
}
}
printf("\n总结:\n");
printf("clock_gettime是现代Linux系统中推荐的高精度计时函数\n");
printf("支持多种时钟类型,满足不同应用场景需求\n");
printf("提供纳秒级精度,优于传统的time和gettimeofday函数\n");
printf("正确使用时钟类型对程序性能和正确性很重要\n");
return 0;
}
clock_nanosleep – 高精度睡眠
函数介绍
clock_nanosleep
系统调用提供纳秒级精度的睡眠功能,支持绝对时间和相对时间两种模式,比传统的nanosleep
更加灵活。
函数原型
#include <time.h>
int clock_nanosleep(clockid_t clock_id, int flags,
const struct timespec *request,
struct timespec *remain);
功能
使进程睡眠指定的时间,支持高精度纳秒级睡眠。
参数
clockid_t clock_id
: 时钟IDint flags
: 标志位0
: 相对时间睡眠TIMER_ABSTIME
: 绝对时间睡眠
const struct timespec *request
: 请求睡眠的时间struct timespec *remain
: 剩余时间(被信号中断时)
返回值
- 成功时返回0
- 被信号中断时返回-1,并设置errno为EINTR
- 失败时返回-1,并设置其他errno
相似函数
nanosleep()
: 纳秒级睡眠sleep()
: 秒级睡眠usleep()
: 微秒级睡眠
示例代码
#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;
}
clock_settime – 设置时钟时间
函数介绍
clock_settime
系统调用用于设置指定时钟的时间值。它允许程序修改系统时钟,主要用于时间同步和系统管理。
函数原型
#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()
: 设置系统时间(已废弃)
示例代码
#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, ¤t_time) == -1) {
perror(" 获取当前时间失败");
} else {
printf(" 当前系统时间: %ld.%09ld 秒\n", current_time.tv_sec, current_time.tv_nsec);
printf(" 对应日期: %s", ctime(¤t_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, ¤t_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, ¤t_time) == 0) {
printf(" UTC时间: %ld.%09ld 秒\n", current_time.tv_sec, current_time.tv_nsec);
// 获取本地时区偏移
struct tm *utc_tm = gmtime(¤t_time.tv_sec);
struct tm *local_tm = localtime(¤t_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;
}