clock_adjtime、clock_getres、clock_gettime、clock_nanosleep、clock_settime系统调用及示例

clock_adjtime - 调整时钟参数

函数介绍

clock_adjtime系统调用用于调整指定时钟的参数,主要用于精密时间同步。它可以设置时钟的频率调整、时间偏移等参数,常用于NTP客户端实现。

函数原型

1
2
3
4
5
6
7
#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: 时钟ID

  • CLOCK_REALTIME: 系统实时钟

  • CLOCK_TAI: 国际原子时

struct timex *buf: 指向timex结构体的指针,包含调整参数

返回值

  • 成功时返回状态码

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

特殊限制

  • 需要CAP_SYS_TIME能力

  • 通常需要root权限

相似函数

  • adjtimex(): 调整系统时钟

  • settimeofday(): 设置系统时间

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#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系统调用用于获取指定时钟的精度(分辨率)。它返回时钟能够表示的最小时间间隔。

函数原型

1
2
3
4
#include <time.h>

int clock_getres(clockid_t clk_id, struct timespec *res);

功能

获取指定时钟的精度,即能够表示的最小时间间隔。

参数

  • clockid_t clk_id: 时钟ID

  • struct timespec *res: 指向timespec结构体的指针,用于存储精度信息

返回值

  • 成功时返回0

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

特似函数

  • clock_gettime(): 获取时钟时间

  • gettimeofday(): 获取系统时间

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
#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&#91;] = {
CLOCK_REALTIME,
CLOCK_MONOTONIC,
CLOCK_PROCESS_CPUTIME_ID,
CLOCK_THREAD_CPUTIME_ID
};

const char *clock_names&#91;] = {
"CLOCK_REALTIME",
"CLOCK_MONOTONIC",
"CLOCK_PROCESS_CPUTIME_ID",
"CLOCK_THREAD_CPUTIME_ID"
};

for (int i = 0; i < 4; i++) {
if (clock_getres(clocks&#91;i], &res) == 0) {
printf(" %-25s: %10ld ns\n", clock_names&#91;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提供了更高的精度和更多的时钟类型选择。

函数原型

1
2
3
4
#include <time.h>

int clock_gettime(clockid_t clk_id, struct timespec *tp);

功能

获取指定时钟的当前时间值。

参数

  • clockid_t clk_id: 时钟ID

  • struct timespec *tp: 指向timespec结构体的指针,用于存储时间信息

返回值

  • 成功时返回0

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

相似函数

  • gettimeofday(): 获取系统时间

  • time(): 获取秒级时间

  • clock_getres(): 获取时钟精度

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
#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&#91;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更加灵活。

函数原型

1
2
3
4
5
6
#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: 请求睡眠的时间

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

struct timespec *remain: 剩余时间(被信号中断时)

返回值

  • 成功时返回0

  • 被信号中断时返回-1,并设置errno为EINTR

  • 失败时返回-1,并设置其他errno

相似函数

  • nanosleep(): 纳秒级睡眠

  • sleep(): 秒级睡眠

  • usleep(): 微秒级睡眠

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
#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&#91;] = {
{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&#91;] = {
"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&#91;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&#91;i].tv_sec * 1000000000LL +
sleep_times&#91;i].tv_nsec;
long long diff = actual - requested;

printf(" %-8s: 请求%8lld ns, 实际%8lld ns, 误差%+6lld ns\n",
time_labels&#91;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系统调用用于设置指定时钟的时间值。它允许程序修改系统时钟,主要用于时间同步和系统管理。

函数原型

1
2
3
4
#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(): 设置系统时间(已废弃)

示例代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
#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;
}
data-ad-format="auto" data-full-width-responsive="true">