Linux调度器函数详解

Linux调度器函数详解

  1. 概述

sched_* 函数族是 Linux 系统中用于进程调度控制的一系列系统调用。可以把调度器想象成”CPU 时间片的分配管理员”——它决定哪个进程什么时候获得 CPU 时间,就像交通警察决定哪辆车什么时候可以通过路口一样。

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

这些函数提供了对进程调度策略、优先级、CPU 亲和性等方面的精细控制,是实现高性能、实时应用的重要工具。

  1. sched_* 函数列表

2.1 基础调度函数

  • sched_yield: 让出当前 CPU 时间片

  • sched_getscheduler: 获取进程调度策略

  • sched_setscheduler: 设置进程调度策略

  • sched_getparam: 获取进程调度参数

  • sched_setparam: 设置进程调度参数

2.2 CPU 亲和性函数

  • sched_getaffinity: 获取进程 CPU 亲和性

  • sched_setaffinity: 设置进程 CPU 亲和性

2.3 优先级函数

  • sched_get_priority_min: 获取指定策略的最小优先级

  • sched_get_priority_max: 获取指定策略的最大优先级

  • sched_rr_get_interval: 获取轮转调度的时间片间隔

2.4 CPU 信息函数

  • sched_getcpu: 获取当前 CPU 编号
  1. 调度策略详解

3.1 调度策略类型

策略值说明SCHED_OTHER0默认分时调度策略(CFS)SCHED_FIFO1先进先出实时调度策略SCHED_RR2轮转实时调度策略SCHED_BATCH3批处理调度策略SCHED_IDLE5空闲调度策略SCHED_DEADLINE6截止时间调度策略

3.2 调度策略特点

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
#include <sched.h>
#include <stdio.h>

void show_scheduling_policies() {
printf("=== 调度策略特点 ===\n");
printf("SCHED_OTHER (默认):\n");
printf(" • 用于普通进程\n");
printf(" • 完全公平调度器 (CFS)\n");
printf(" • 动态优先级调整\n");
printf(" • 适合交互式应用\n\n");

printf("SCHED_FIFO (实时 FIFO):\n");
printf(" • 实时调度策略\n");
printf(" • 高优先级进程一直运行直到阻塞或主动让出\n");
printf(" • 不会时间片轮转\n");
printf(" • 需要 root 权限\n\n");

printf("SCHED_RR (实时轮转):\n");
printf(" • 实时调度策略\n");
printf(" • 时间片轮转调度\n");
printf(" • 相同优先级进程轮流执行\n");
printf(" • 需要 root 权限\n\n");

printf("SCHED_BATCH (批处理):\n");
printf(" • 用于批处理任务\n");
printf(" • 减少唤醒频率\n");
printf(" • 适合长时间运行的非交互任务\n\n");

printf("SCHED_IDLE (空闲):\n");
printf(" • 用于极低优先级任务\n");
printf(" • 只在系统空闲时运行\n");
printf(" • 不影响其他进程\n\n");

printf("SCHED_DEADLINE (截止时间):\n");
printf(" • 基于截止时间的调度\n");
printf(" • 确保任务按时完成\n");
printf(" • 需要特殊配置\n");
printf(" • Linux 3.14+\n\n");
}

  1. 函数详细介绍

4.1 sched_yield - 让出 CPU 时间片

函数原型

1
2
3
#include <sched.h>
int sched_yield(void);

功能

让出当前进程的 CPU 时间片,允许其他同优先级的进程运行。

参数

无参数

返回值

  • 成功: 返回 0

  • 失败: 返回 -1(实际上很少失败)

示例代码

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
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <time.h>
#include <errno.h>

// 消耗 CPU 的函数
void consume_cpu(int seconds) {
time_t start = time(NULL);
volatile long sum = 0;

while (time(NULL) - start < seconds) {
for (long i = 0; i < 1000000; i++) {
sum += i;
}
}
}

int main() {
printf("=== sched_yield 示例 ===\n\n");

// 获取当前进程 ID 和 CPU 信息
printf("进程 ID: %d\n", getpid());
printf("父进程 ID: %d\n", getppid());

// 获取当前 CPU 编号(如果有支持)
int current_cpu = sched_getcpu();
if (current_cpu != -1) {
printf("当前 CPU: %d\n", current_cpu);
} else {
printf("无法获取当前 CPU 信息\n");
}

printf("\n1. 不使用 sched_yield 的 CPU 消耗:\n");
printf(" 开始消耗 CPU 时间...\n");

time_t start_time = time(NULL);
consume_cpu(3); // 消耗 3 秒 CPU 时间
time_t end_time = time(NULL);

printf(" 消耗完成,用时 %ld 秒\n", end_time - start_time);

printf("\n2. 使用 sched_yield 的 CPU 消耗:\n");
printf(" 开始消耗 CPU 时间并让出时间片...\n");

start_time = time(NULL);
time_t yield_start = time(NULL);

while (time(NULL) - yield_start < 3) {
// 消耗一些 CPU 时间
volatile long sum = 0;
for (long i = 0; i < 500000; i++) {
sum += i;
}

// 让出 CPU 时间片
if (sched_yield() == -1) {
perror("sched_yield 失败");
}
}

end_time = time(NULL);
printf(" 消耗完成,用时 %ld 秒\n", end_time - start_time);

printf("\n3. sched_yield 的实际效果:\n");
printf(" • 允许其他同优先级进程运行\n");
printf(" • 改善系统响应性\n");
printf(" • 减少饥饿现象\n");
printf(" • 适合协作式多任务\n");

printf("\n=== sched_yield 使用场景 ===\n");
printf("1. 长时间运行的循环\n");
printf("2. 忙等待循环\n");
printf("3. 协作式多任务\n");
printf("4. 实时应用中的主动让出\n");
printf("5. 负载均衡\n");

printf("\n=== 注意事项 ===\n");
printf("1. 不保证立即切换到其他进程\n");
printf("2. 只影响同优先级进程\n");
printf("3. 过度使用可能影响性能\n");
printf("4. 不是强制调度切换\n");
printf("5. 应该谨慎使用\n");

return 0;
}

4.2 sched_getscheduler/sched_setscheduler - 调度策略控制

函数原型

1
2
3
4
5
#include <sched.h>

int sched_getscheduler(pid_t pid);
int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param);

sched_param 结构体

1
2
3
4
5
struct sched_param {
int sched_priority; // 调度优先级
// 对于 SCHED_DEADLINE,还有额外字段
};

功能

  • sched_getscheduler: 获取指定进程的调度策略

  • sched_setscheduler: 设置指定进程的调度策略和参数

参数

  • pid: 进程 ID(0 表示当前进程)

  • policy: 调度策略

  • param: 指向调度参数的指针

返回值

  • sched_getscheduler: 成功返回调度策略,失败返回 -1

  • sched_setscheduler: 成功返回 0,失败返回 -1

示例代码

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
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <errno.h>
#include <string.h>
#include <sys/resource.h>

// 将调度策略转换为字符串
const char* policy_to_string(int policy) {
switch (policy) {
case SCHED_OTHER: return "SCHED_OTHER (默认)";
case SCHED_FIFO: return "SCHED_FIFO (实时FIFO)";
case SCHED_RR: return "SCHED_RR (实时轮转)";
case SCHED_BATCH: return "SCHED_BATCH (批处理)";
case SCHED_IDLE: return "SCHED_IDLE (空闲)";
case SCHED_DEADLINE: return "SCHED_DEADLINE (截止时间)";
default: return "未知策略";
}
}

// 显示进程调度信息
void show_process_scheduling_info(pid_t pid, const char *description) {
printf("=== %s ===\n", description);

if (pid == 0) {
printf("进程: 当前进程 (PID: %d)\n", getpid());
} else {
printf("进程: PID %d\n", pid);
}

// 获取调度策略
int policy = sched_getscheduler(pid);
if (policy == -1) {
perror("获取调度策略失败");
return;
}

printf("调度策略: %s\n", policy_to_string(policy));

// 获取调度参数
struct sched_param param;
if (sched_getparam(pid, &param) == 0) {
printf("调度优先级: %d\n", param.sched_priority);

// 显示优先级范围
int min_priority = sched_get_priority_min(policy);
int max_priority = sched_get_priority_max(policy);

if (min_priority != -1 && max_priority != -1) {
printf("优先级范围: %d - %d\n", min_priority, max_priority);

if (param.sched_priority < min_priority || param.sched_priority > max_priority) {
printf("⚠ 当前优先级超出范围\n");
}
}
} else {
perror("获取调度参数失败");
}

// 获取进程优先级
errno = 0;
int nice_value = getpriority(PRIO_PROCESS, pid);
if (errno == 0) {
printf("Nice 值: %d\n", nice_value);
}

printf("\n");
}

// 设置调度策略
int set_process_scheduling_policy(pid_t pid, int policy, int priority) {
struct sched_param param;
param.sched_priority = priority;

printf("设置进程调度策略:\n");
printf(" 进程 ID: %d\n", pid ? pid : getpid());
printf(" 调度策略: %s\n", policy_to_string(policy));
printf(" 调度优先级: %d\n", priority);

if (sched_setscheduler(pid, policy, &param) == 0) {
printf("✓ 调度策略设置成功\n");
return 0;
} else {
switch (errno) {
case EPERM:
printf("✗ 权限不足: 需要 root 权限设置实时策略\n");
break;
case EINVAL:
printf("✗ 参数无效: 策略或优先级无效\n");
break;
case ESRCH:
printf("✗ 进程不存在\n");
break;
default:
printf("✗ 设置失败: %s\n", strerror(errno));
break;
}
return -1;
}
}

int main() {
printf("=== sched_getscheduler/sched_setscheduler 示例 ===\n\n");

// 显示当前用户信息
printf("用户信息:\n");
printf(" UID: %d\n", getuid());
printf(" EUID: %d\n", geteuid());
printf(" GID: %d\n", getgid());
printf(" EGID: %d\n", getegid());
printf("\n");

// 显示初始调度信息
show_process_scheduling_info(0, "初始调度信息");

// 显示各种调度策略的优先级范围
printf("=== 各种调度策略的优先级范围 ===\n");

int policies&#91;] = {SCHED_OTHER, SCHED_FIFO, SCHED_RR, SCHED_BATCH, SCHED_IDLE};
int num_policies = sizeof(policies) / sizeof(policies&#91;0]);

for (int i = 0; i < num_policies; i++) {
int min_priority = sched_get_priority_min(policies&#91;i]);
int max_priority = sched_get_priority_max(policies&#91;i]);

printf("%-20s: 最小优先级 %3d, 最大优先级 %3d\n",
policy_to_string(policies&#91;i]), min_priority, max_priority);
}
printf("\n");

// 演示调度策略设置(需要 root 权限)
printf("=== 调度策略设置演示 ===\n");

// 1. 尝试设置 SCHED_FIFO(需要 root 权限)
printf("1. 尝试设置 SCHED_FIFO 策略:\n");
if (set_process_scheduling_policy(0, SCHED_FIFO, 10) == 0) {
show_process_scheduling_info(0, "设置 SCHED_FIFO 后");
} else {
printf(" 说明: SCHED_FIFO 需要 root 权限\n");
}

// 2. 尝试设置 SCHED_RR(需要 root 权限)
printf("\n2. 尝试设置 SCHED_RR 策略:\n");
if (set_process_scheduling_policy(0, SCHED_RR, 15) == 0) {
show_process_scheduling_info(0, "设置 SCHED_RR 后");
} else {
printf(" 说明: SCHED_RR 需要 root 权限\n");
}

// 3. 尝试设置 SCHED_BATCH
printf("\n3. 尝试设置 SCHED_BATCH 策略:\n");
if (set_process_scheduling_policy(0, SCHED_BATCH, 0) == 0) {
show_process_scheduling_info(0, "设置 SCHED_BATCH 后");
} else {
printf(" 说明: 可能需要适当权限\n");
}

// 4. 恢复默认策略
printf("\n4. 恢复默认 SCHED_OTHER 策略:\n");
struct sched_param default_param = {0};
if (sched_setscheduler(0, SCHED_OTHER, &default_param) == 0) {
printf("✓ 成功恢复默认调度策略\n");
show_process_scheduling_info(0, "恢复默认策略后");
} else {
printf("✗ 恢复默认策略失败: %s\n", strerror(errno));
}

printf("\n=== 调度策略使用建议 ===\n");
printf("选择原则:\n");
printf("1. 普通应用: 使用 SCHED_OTHER(默认)\n");
printf("2. 实时应用: 使用 SCHED_FIFO 或 SCHED_RR\n");
printf("3. 批处理任务: 使用 SCHED_BATCH\n");
printf("4. 后台任务: 使用 SCHED_IDLE\n");
printf("5. 截止时间任务: 使用 SCHED_DEADLINE\n");
printf("\n");

printf("权限要求:\n");
printf("1. SCHED_OTHER/SCHED_BATCH/SCHED_IDLE: 普通权限\n");
printf("2. SCHED_FIFO/SCHED_RR: 需要 root 权限\n");
printf("3. SCHED_DEADLINE: 需要特殊配置\n");
printf("\n");

printf("性能影响:\n");
printf("1. 实时策略: 更高优先级,更低延迟\n");
printf("2. 批处理策略: 更低唤醒频率,更好吞吐\n");
printf("3. 空闲策略: 不影响其他进程\n");
printf("4. 默认策略: 平衡性能和公平性\n");

return 0;
}

4.3 sched_getaffinity/sched_setaffinity - CPU 亲和性控制

函数原型

1
2
3
4
5
6
#define _GNU_SOURCE
#include <sched.h>

int sched_getaffinity(pid_t pid, size_t cpusetsize, cpu_set_t *mask);
int sched_setaffinity(pid_t pid, size_t cpusetsize, const cpu_set_t *mask);

CPU 集合操作宏

1
2
3
4
5
6
void CPU_ZERO(cpu_set_t *set);              // 清空 CPU 集合
void CPU_SET(int cpu, cpu_set_t *set); // 设置 CPU
void CPU_CLR(int cpu, cpu_set_t *set); // 清除 CPU
int CPU_ISSET(int cpu, cpu_set_t *set); // 检查 CPU 是否设置
int CPU_COUNT(cpu_set_t *set); // 计算设置的 CPU 数量

功能

  • sched_getaffinity: 获取进程的 CPU 亲和性掩码

  • sched_setaffinity: 设置进程的 CPU 亲和性掩码

参数

  • pid: 进程 ID(0 表示当前进程)

  • cpusetsize: CPU 集合的大小

  • mask: 指向 CPU 集合的指针

返回值

  • 成功: 返回 0

  • 失败: 返回 -1,并设置相应的 errno

示例代码

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
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <errno.h>
#include <string.h>

// 显示 CPU 集合信息
void show_cpu_set_info(const cpu_set_t *cpu_set, const char *description) {
printf("=== %s ===\n", description);

int cpu_count = CPU_COUNT((cpu_set_t*)cpu_set);
printf("CPU 数量: %d\n", cpu_count);

printf("CPU 列表: ");
int printed = 0;
for (int i = 0; i < CPU_SETSIZE; i++) {
if (CPU_ISSET(i, (cpu_set_t*)cpu_set)) {
if (printed > 0) printf(", ");
printf("%d", i);
printed++;
}
}
if (printed == 0) {
printf("无");
}
printf("\n\n");
}

// 获取系统 CPU 信息
void show_system_cpu_info() {
printf("=== 系统 CPU 信息 ===\n");

// 获取在线 CPU 数量
int online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
printf("在线 CPU 数量: %d\n", online_cpus);

// 获取配置的 CPU 数量
int conf_cpus = sysconf(_SC_NPROCESSORS_CONF);
printf("配置 CPU 数量: %d\n", conf_cpus);

// 显示当前进程的 CPU 亲和性
cpu_set_t current_set;
CPU_ZERO(&current_set);

if (sched_getaffinity(0, sizeof(current_set), &current_set) == 0) {
show_cpu_set_info(&current_set, "当前进程 CPU 亲和性");
} else {
perror("获取 CPU 亲和性失败");
}
}

// 设置 CPU 亲和性
int set_process_cpu_affinity(pid_t pid, const int *cpu_list, int cpu_count) {
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);

printf("设置 CPU 亲和性:\n");
printf(" 进程 ID: %d\n", pid ? pid : getpid());
printf(" CPU 列表: ");

for (int i = 0; i < cpu_count; i++) {
if (i > 0) printf(", ");
printf("%d", cpu_list&#91;i]);
CPU_SET(cpu_list&#91;i], &cpu_set);
}
printf("\n");

if (sched_setaffinity(pid, sizeof(cpu_set), &cpu_set) == 0) {
printf("✓ CPU 亲和性设置成功\n");
return 0;
} else {
printf("✗ CPU 亲和性设置失败: %s\n", strerror(errno));
return -1;
}
}

// 创建 CPU 绑定的测试线程
void* cpu_bound_worker(void *arg) {
int worker_id = *(int*)arg;

printf("工作线程 %d 启动\n", worker_id);

// 获取线程的 CPU 信息
int current_cpu = sched_getcpu();
if (current_cpu != -1) {
printf(" 工作线程 %d 运行在 CPU %d 上\n", worker_id, current_cpu);
}

// 执行一些 CPU 密集型任务
volatile long sum = 0;
for (long i = 0; i < 10000000; i++) {
sum += i;

// 偶尔检查 CPU 变化
if (i % 1000000 == 0) {
int new_cpu = sched_getcpu();
if (new_cpu != current_cpu && new_cpu != -1) {
printf(" 工作线程 %d 从 CPU %d 切换到 CPU %d\n",
worker_id, current_cpu, new_cpu);
current_cpu = new_cpu;
}
}
}

printf("工作线程 %d 完成\n", worker_id);
return NULL;
}

int main() {
printf("=== sched_getaffinity/sched_setaffinity 示例 ===\n\n");

// 显示系统信息
show_system_cpu_info();

// 1. 获取当前进程的 CPU 亲和性
printf("1. 获取当前进程 CPU 亲和性:\n");
cpu_set_t initial_set;
CPU_ZERO(&initial_set);

if (sched_getaffinity(0, sizeof(initial_set), &initial_set) == 0) {
show_cpu_set_info(&initial_set, "初始 CPU 亲和性");
} else {
perror("获取初始 CPU 亲和性失败");
}

// 2. 设置 CPU 亲和性(绑定到特定 CPU)
printf("2. 设置 CPU 亲和性:\n");

// 获取系统 CPU 数量
int online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
printf("系统在线 CPU 数量: %d\n", online_cpus);

if (online_cpus > 1) {
// 绑定到第一个 CPU
int single_cpu&#91;] = {0};
if (set_process_cpu_affinity(0, single_cpu, 1) == 0) {
cpu_set_t new_set;
CPU_ZERO(&new_set);

if (sched_getaffinity(0, sizeof(new_set), &new_set) == 0) {
show_cpu_set_info(&new_set, "设置后 CPU 亲和性");
}
}

// 绑定到前两个 CPU
printf("绑定到前两个 CPU:\n");
int two_cpus&#91;] = {0, 1};
if (set_process_cpu_affinity(0, two_cpus, 2) == 0) {
cpu_set_t new_set;
CPU_ZERO(&new_set);

if (sched_getaffinity(0, sizeof(new_set), &new_set) == 0) {
show_cpu_set_info(&new_set, "绑定到前两个 CPU 后");
}
}
} else {
printf("系统只有一个 CPU,跳过 CPU 绑定测试\n");
}

// 3. 恢复初始 CPU 亲和性
printf("3. 恢复初始 CPU 亲和性:\n");
if (sched_setaffinity(0, sizeof(initial_set), &initial_set) == 0) {
printf("✓ 成功恢复初始 CPU 亲和性\n");

cpu_set_t restored_set;
CPU_ZERO(&restored_set);

if (sched_getaffinity(0, sizeof(restored_set), &restored_set) == 0) {
show_cpu_set_info(&restored_set, "恢复后 CPU 亲和性");
}
} else {
printf("✗ 恢复初始 CPU 亲和性失败: %s\n", strerror(errno));
}

// 4. 显示 CPU 亲和性的好处
printf("=== CPU 亲和性的好处 ===\n");
printf("性能优化:\n");
printf("1. 减少 CPU 缓存失效\n");
printf("2. 提高缓存命中率\n");
printf("3. 降低上下文切换开销\n");
printf("4. 改善 NUMA 访问模式\n");
printf("5. 提高多核应用性能\n");
printf("\n");

printf("应用场景:\n");
printf("1. 高性能计算应用\n");
printf("2. 实时系统\n");
printf("3. 数据库服务器\n");
printf("4. 游戏服务器\n");
printf("5. 科学计算\n");
printf("6. 音视频处理\n");
printf("\n");

printf("注意事项:\n");
printf("1. 过度限制可能影响负载均衡\n");
printf("2. NUMA 架构需要考虑内存亲和性\n");
printf("3. 应该根据应用特点合理设置\n");
printf("4. 避免与其他进程争抢 CPU\n");
printf("5. 监控系统整体性能\n");

return 0;
}

4.4 sched_get_priority_min/sched_get_priority_max - 优先级范围查询

函数原型

1
2
3
4
5
#include <sched.h>

int sched_get_priority_min(int policy);
int sched_get_priority_max(int policy);

功能

获取指定调度策略的最小和最大优先级值。

参数

  • policy: 调度策略

返回值

  • 成功: 返回对应的优先级值

  • 失败: 返回 -1,并设置相应的 errno

示例代码

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
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <errno.h>
#include <string.h>

// 显示调度策略优先级范围
void show_policy_priority_range(int policy, const char *policy_name) {
int min_priority = sched_get_priority_min(policy);
int max_priority = sched_get_priority_max(policy);

printf("%-20s: ", policy_name);

if (min_priority == -1 || max_priority == -1) {
printf("不支持 (%s)\n", strerror(errno));
} else {
printf("最小优先级 %3d, 最大优先级 %3d", min_priority, max_priority);

if (min_priority == max_priority) {
printf(" (固定优先级)");
} else if (min_priority < max_priority) {
printf(" (动态优先级范围)");
}
printf("\n");
}
}

// 显示所有调度策略的优先级范围
void show_all_policy_ranges() {
printf("=== 所有调度策略优先级范围 ===\n");

struct {
int policy;
const char *name;
} policies&#91;] = {
{SCHED_OTHER, "SCHED_OTHER"},
{SCHED_FIFO, "SCHED_FIFO"},
{SCHED_RR, "SCHED_RR"},
{SCHED_BATCH, "SCHED_BATCH"},
{SCHED_IDLE, "SCHED_IDLE"},
{SCHED_DEADLINE, "SCHED_DEADLINE"},
{-1, NULL}
};

for (int i = 0; policies&#91;i].name; i++) {
show_policy_priority_range(policies&#91;i].policy, policies&#91;i].name);
}

printf("\n");
}

// 优先级验证函数
int validate_priority_for_policy(int policy, int priority) {
int min_priority = sched_get_priority_min(policy);
int max_priority = sched_get_priority_max(policy);

if (min_priority == -1 || max_priority == -1) {
return -1; // 策略不支持
}

if (priority >= min_priority && priority <= max_priority) {
return 0; // 优先级有效
} else {
return 1; // 优先级无效
}
}

// 显示优先级验证结果
void show_priority_validation(int policy, int priority) {
const char *policy_name = NULL;
switch (policy) {
case SCHED_OTHER: policy_name = "SCHED_OTHER"; break;
case SCHED_FIFO: policy_name = "SCHED_FIFO"; break;
case SCHED_RR: policy_name = "SCHED_RR"; break;
case SCHED_BATCH: policy_name = "SCHED_BATCH"; break;
case SCHED_IDLE: policy_name = "SCHED_IDLE"; break;
case SCHED_DEADLINE: policy_name = "SCHED_DEADLINE"; break;
default: policy_name = "未知策略"; break;
}

printf("验证 %s 策略优先级 %d: ", policy_name, priority);

int result = validate_priority_for_policy(policy, priority);
switch (result) {
case -1:
printf("策略不支持\n");
break;
case 0:
printf("✓ 有效\n");
break;
case 1:
printf("✗ 无效\n");
break;
}
}

int main() {
printf("=== sched_get_priority_min/max 示例 ===\n\n");

// 显示所有策略的优先级范围
show_all_policy_ranges();

// 显示当前进程信息
printf("当前进程信息:\n");
printf(" 进程 ID: %d\n", getpid());
printf(" 父进程 ID: %d\n", getppid());
printf(" 用户 ID: %d\n", getuid());
printf(" 组 ID: %d\n", getgid());

// 获取当前进程调度策略
int current_policy = sched_getscheduler(0);
if (current_policy != -1) {
printf(" 当前调度策略: %d ", current_policy);
switch (current_policy) {
case SCHED_OTHER: printf("(SCHED_OTHER)\n"); break;
case SCHED_FIFO: printf("(SCHED_FIFO)\n"); break;
case SCHED_RR: printf("(SCHED_RR)\n"); break;
case SCHED_BATCH: printf("(SCHED_BATCH)\n"); break;
case SCHED_IDLE: printf("(SCHED_IDLE)\n"); break;
case SCHED_DEADLINE: printf("(SCHED_DEADLINE)\n"); break;
default: printf("(未知)\n"); break;
}

// 获取当前进程优先级
struct sched_param current_param;
if (sched_getparam(0, &current_param) == 0) {
printf(" 当前优先级: %d\n", current_param.sched_priority);

// 验证当前优先级
show_priority_validation(current_policy, current_param.sched_priority);
}
} else {
perror("获取当前调度策略失败");
}

printf("\n");

// 验证不同策略的优先级
printf("=== 优先级验证示例 ===\n");

// SCHED_OTHER 策略
printf("SCHED_OTHER 策略:\n");
show_priority_validation(SCHED_OTHER, 0); // 有效
show_priority_validation(SCHED_OTHER, -1); // 无效
show_priority_validation(SCHED_OTHER, 10); // 无效

// SCHED_FIFO 策略
printf("\nSCHED_FIFO 策略:\n");
show_priority_validation(SCHED_FIFO, 10); // 可能有效
show_priority_validation(SCHED_FIFO, 50); // 可能有效
show_priority_validation(SCHED_FIFO, 99); // 可能有效
show_priority_validation(SCHED_FIFO, 100); // 可能无效

// SCHED_RR 策略
printf("\nSCHED_RR 策略:\n");
show_priority_validation(SCHED_RR, 10); // 可能有效
show_priority_validation(SCHED_RR, 50); // 可能有效
show_priority_validation(SCHED_RR, 99); // 可能有效
show_priority_validation(SCHED_RR, 100); // 可能无效

// SCHED_BATCH 策略
printf("\nSCHED_BATCH 策略:\n");
show_priority_validation(SCHED_BATCH, 0); // 有效
show_priority_validation(SCHED_BATCH, -1); // 无效
show_priority_validation(SCHED_BATCH, 10); // 无效

// SCHED_IDLE 策略
printf("\nSCHED_IDLE 策略:\n");
show_priority_validation(SCHED_IDLE, 0); // 有效
show_priority_validation(SCHED_IDLE, -1); // 无效
show_priority_validation(SCHED_IDLE, 10); // 无效

printf("\n=== 优先级使用建议 ===\n");
printf("优先级设置原则:\n");
printf("1. 了解策略的优先级范围\n");
printf("2. 合理分配优先级值\n");
printf("3. 避免优先级反转\n");
printf("4. 考虑系统整体平衡\n");
printf("5. 验证优先级的有效性\n");
printf("\n");

printf("实时策略优先级:\n");
printf("1. SCHED_FIFO/SCHED_RR: 1-99 (通常)\n");
printf("2. 数值越大优先级越高\n");
printf("3. 需要 root 权限\n");
printf("4. 谨慎使用高优先级\n");
printf("5. 避免独占 CPU\n");
printf("\n");

printf("普通策略优先级:\n");
printf("1. SCHED_OTHER: 通常为 0\n");
printf("2. 通过 nice 值调整\n");
printf("3. 使用动态优先级\n");
printf("4. 平衡系统负载\n");
printf("5. 适合交互式应用\n");

return 0;
}

4.5 sched_rr_get_interval - 轮转调度时间片

函数原型

1
2
3
4
#include <sched.h>

int sched_rr_get_interval(pid_t pid, struct timespec *tp);

功能

获取 SCHED_RR 策略的时间片长度。

参数

  • pid: 进程 ID(0 表示当前进程)

  • tp: 指向 timespec 结构体的指针,用于存储时间片长度

返回值

  • 成功: 返回 0

  • 失败: 返回 -1,并设置相应的 errno

示例代码

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
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <errno.h>
#include <string.h>
#include <time.h>

// 显示时间片信息
void show_timeslice_info(const struct timespec *interval, const char *description) {
printf("=== %s ===\n", description);

if (interval->tv_sec == 0 && interval->tv_nsec == 0) {
printf("时间片长度: 未设置\n");
} else {
printf("时间片长度: %ld.%09ld 秒\n",
(long)interval->tv_sec, (long)interval->tv_nsec);
printf("时间片长度: %.3f 毫秒\n",
(double)interval->tv_sec * 1000 + (double)interval->tv_nsec / 1000000);
printf("时间片长度: %.3f 微秒\n",
(double)interval->tv_sec * 1000000 + (double)interval->tv_nsec / 1000);
printf("时间片长度: %ld 纳秒\n",
(long)interval->tv_sec * 1000000000 + (long)interval->tv_nsec);
}

printf("\n");
}

// 获取 RR 调度时间片
int get_rr_timeslice(pid_t pid) {
struct timespec interval;

printf("获取 SCHED_RR 时间片长度:\n");
printf(" 进程 ID: %d\n", pid ? pid : getpid());

if (sched_rr_get_interval(pid, &interval) == 0) {
show_timeslice_info(&interval, "RR 调度时间片");
return 0;
} else {
switch (errno) {
case EINVAL:
printf("✗ 进程不是 SCHED_RR 策略\n");
break;
case ESRCH:
printf("✗ 进程不存在\n");
break;
default:
printf("✗ 获取时间片失败: %s\n", strerror(errno));
break;
}
return -1;
}
}

// 比较不同策略的时间片
void compare_policy_intervals() {
printf("=== 不同策略时间片比较 ===\n");

// 获取当前进程时间片(假设是 SCHED_OTHER)
struct timespec current_interval;
if (sched_rr_get_interval(0, &current_interval) == 0) {
printf("当前进程时间片: %ld.%09ld 秒\n",
(long)current_interval.tv_sec, (long)current_interval.tv_nsec);
} else {
printf("当前进程时间片: 无法获取 (%s)\n", strerror(errno));
}

// 显示系统时间片配置
printf("\n系统时间片配置:\n");

// 读取内核参数
FILE *fp = fopen("/proc/sys/kernel/sched_rr_timeslice_ms", "r");
if (fp) {
char buffer&#91;64];
if (fgets(buffer, sizeof(buffer), fp)) {
printf(" RR 时间片 (ms): %s", buffer);
}
fclose(fp);
} else {
printf(" RR 时间片: 无法读取系统配置\n");
}

// 显示其他相关配置
printf("其他相关配置:\n");
system("cat /proc/sys/kernel/sched_child_runs_first 2>/dev/null || echo ' 无法读取 sched_child_runs_first'");
system("cat /proc/sys/kernel/sched_autogroup_enabled 2>/dev/null || echo ' 无法读取 sched_autogroup_enabled'");

printf("\n");
}

int main() {
printf("=== sched_rr_get_interval 示例 ===\n\n");

// 显示系统信息
printf("系统信息:\n");
printf(" 内核版本: ");
system("uname -r | tr -d '\\n'");
printf("\n");
printf(" CPU 架构: ");
system("uname -m | tr -d '\\n'");
printf("\n");
printf(" 进程 ID: %d\n", getpid());
printf(" 父进程 ID: %d\n", getppid());
printf("\n");

// 1. 获取当前进程时间片
printf("1. 获取当前进程时间片:\n");
get_rr_timeslice(0);

// 2. 尝试获取不存在进程的时间片
printf("2. 尝试获取不存在进程的时间片:\n");
if (sched_rr_get_interval(999999, &(struct timespec){0}) == -1) {
if (errno == ESRCH) {
printf("✓ 正确处理不存在进程: ESRCH\n");
} else {
printf("✗ 意外错误: %s\n", strerror(errno));
}
}

// 3. 尝试获取非 RR 策略进程的时间片
printf("3. 尝试获取非 RR 策略进程的时间片:\n");
if (sched_rr_get_interval(0, &(struct timespec){0}) == -1) {
if (errno == EINVAL) {
printf("✓ 正确处理非 RR 策略进程: EINVAL\n");
printf(" 说明: 当前进程使用默认 SCHED_OTHER 策略\n");
} else {
printf("✗ 其他错误: %s\n", strerror(errno));
}
}

// 4. 显示系统时间片配置
compare_policy_intervals();

// 5. 显示时间片对性能的影响
printf("=== 时间片对性能的影响 ===\n");
printf("时间片长度的影响:\n");
printf("1. 较短时间片:\n");
printf(" • 更好的响应性\n");
printf(" • 更多上下文切换\n");
printf(" • 更低吞吐量\n");
printf(" • 更高延迟\n");
printf("\n");

printf("2. 较长时间片:\n");
printf(" • 更低响应性\n");
printf(" • 更少上下文切换\n");
printf(" • 更高吞吐量\n");
printf(" • 更低延迟\n");
printf("\n");

printf("3. 默认时间片:\n");
printf(" • 平衡响应性和吞吐量\n");
printf(" • 通常为 10-100ms\n");
printf(" • 适应大多数应用\n");
printf(" • 可配置调整\n");
printf("\n");

printf("应用场景:\n");
printf("1. 实时系统: 需要短时间片保证响应性\n");
printf("2. 批处理系统: 需要长时间片提高吞吐量\n");
printf("3. 交互式应用: 需要适中时间片平衡各方面\n");
printf("4. 服务器应用: 根据负载动态调整\n");
printf("5. 嵌入式系统: 根据硬件特性优化\n");
printf("\n");

printf("配置建议:\n");
printf("1. 监控上下文切换频率\n");
printf("2. 调整时间片适应应用特点\n");
printf("3. 考虑系统整体负载\n");
printf("4. 测试不同配置的性能\n");
printf("5. 避免极端配置影响系统稳定性\n");

return 0;
}

4.6 sched_getcpu - 获取当前 CPU 编号

函数原型

1
2
3
4
5
#define _GNU_SOURCE
#include <sched.h>

int sched_getcpu(void);

功能

获取调用线程当前运行的 CPU 编号。

参数

无参数

返回值

  • 成功: 返回 CPU 编号(从 0 开始)

  • 失败: 返回 -1,并设置相应的 errno

示例代码

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
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sched.h>
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <sys/syscall.h>

// 获取 CPU 信息的辅助函数
void show_cpu_info() {
printf("=== CPU 信息 ===\n");

// 获取当前 CPU 编号
int current_cpu = sched_getcpu();
if (current_cpu != -1) {
printf("当前 CPU 编号: %d\n", current_cpu);
} else {
printf("无法获取当前 CPU 编号: %s\n", strerror(errno));
}

// 获取系统 CPU 数量
long online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
long conf_cpus = sysconf(_SC_NPROCESSORS_CONF);

printf("在线 CPU 数量: %ld\n", online_cpus);
printf("配置 CPU 数量: %ld\n", conf_cpus);

// 显示 CPU 信息
printf("CPU 详细信息:\n");
system("lscpu | head -10 2>/dev/null || echo '无法获取 CPU 详细信息'");

printf("\n");
}

// 线程函数,显示线程的 CPU 信息
void* thread_cpu_info(void* arg) {
int thread_id = *(int*)arg;
int initial_cpu, current_cpu;

// 获取初始 CPU
initial_cpu = sched_getcpu();

printf("线程 %d:\n", thread_id);
printf(" 初始 CPU: %d\n", initial_cpu);

// 执行一些工作并检查 CPU 变化
volatile long sum = 0;
for (long i = 0; i < 10000000; i++) {
sum += i;

// 偶尔检查 CPU 变化
if (i % 1000000 == 0) {
current_cpu = sched_getcpu();
if (current_cpu != initial_cpu && current_cpu != -1) {
printf(" 线程 %d 从 CPU %d 切换到 CPU %d\n",
thread_id, initial_cpu, current_cpu);
initial_cpu = current_cpu;
}
}
}

// 最终 CPU
current_cpu = sched_getcpu();
printf(" 最终 CPU: %d\n", current_cpu);
printf(" 线程 %d 完成\n", thread_id);

return NULL;
}

// CPU 绑定测试
void test_cpu_binding() {
printf("=== CPU 绑定测试 ===\n");

// 获取系统 CPU 数量
long online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
if (online_cpus <= 1) {
printf("系统只有一个 CPU,跳过绑定测试\n");
return;
}

// 创建多个线程
pthread_t threads&#91;4];
int thread_ids&#91;4] = {1, 2, 3, 4};

printf("创建 4 个线程进行 CPU 绑定测试:\n");

for (int i = 0; i < 4; i++) {
if (pthread_create(&threads&#91;i], NULL, thread_cpu_info, &thread_ids&#91;i]) != 0) {
perror("创建线程失败");
return;
}
}

// 等待所有线程完成
for (int i = 0; i < 4; i++) {
pthread_join(threads&#91;i], NULL);
}

printf("CPU 绑定测试完成\n\n");
}

int main() {
printf("=== sched_getcpu 示例 ===\n\n");

// 显示系统信息
show_cpu_info();

// 显示当前进程信息
printf("进程信息:\n");
printf(" 进程 ID: %d\n", getpid());
printf(" 父进程 ID: %d\n", getppid());
printf(" 线程 ID: %ld\n", syscall(SYS_gettid));

// 获取当前 CPU
int current_cpu = sched_getcpu();
if (current_cpu != -1) {
printf(" 当前运行 CPU: %d\n", current_cpu);
} else {
printf(" 无法获取 CPU 信息: %s\n", strerror(errno));
}

printf("\n");

// 连续获取 CPU 信息观察变化
printf("连续获取 CPU 信息 (执行密集计算):\n");
volatile long sum = 0;
int initial_cpu = sched_getcpu();

printf(" 初始 CPU: %d\n", initial_cpu);

for (long i = 0; i < 50000000; i++) {
sum += i;

// 每隔一定次数检查 CPU
if (i % 10000000 == 0) {
int current_cpu = sched_getcpu();
if (current_cpu != -1) {
printf(" 计算 %ld 次后 CPU: %d\n", i, current_cpu);
}
}
}

int final_cpu = sched_getcpu();
printf(" 最终 CPU: %d\n", final_cpu);

if (initial_cpu != final_cpu && initial_cpu != -1 && final_cpu != -1) {
printf(" ✓ CPU 在计算过程中发生了切换\n");
} else {
printf(" CPU 在计算过程中保持不变\n");
}

printf("\n");

// CPU 绑定测试
test_cpu_binding();

// 显示 CPU 调度信息
printf("=== CPU 调度信息 ===\n");
printf("CPU 调度相关概念:\n");
printf("1. CPU 亲和性: 进程可以运行的 CPU 集合\n");
printf("2. 负载均衡: 系统在 CPU 间分配负载\n");
printf("3. 上下文切换: 进程在 CPU 间的切换\n");
printf("4. 缓存局部性: 数据在 CPU 缓存中的位置\n");
printf("5. NUMA 拓扑: 非统一内存访问架构\n");
printf("\n");

printf("sched_getcpu 的用途:\n");
printf("1. 性能分析: 监控线程 CPU 使用情况\n");
printf("2. 负载均衡: 了解 CPU 分配情况\n");
printf("3. 调试工具: 分析程序执行行为\n");
printf("4. 实时系统: 监控实时性约束\n");
printf("5. 优化建议: 识别性能瓶颈\n");
printf("\n");

printf("使用建议:\n");
printf("1. 结合 CPU 亲和性使用\n");
printf("2. 监控 CPU 切换频率\n");
printf("3. 分析热点 CPU\n");
printf("4. 优化缓存局部性\n");
printf("5. 避免过度绑定 CPU\n");

return 0;
}

  1. 编译和运行说明
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 编译所有示例程序
gcc -o pread_example pread_example.c
gcc -o affinity_example affinity_example.c
gcc -o priority_example priority_example.c
gcc -o rr_interval_example rr_interval_example.c
gcc -o getcpu_example getcpu_example.c -lpthread

# 运行示例程序
./pread_example
./affinity_example
./priority_example
./rr_interval_example
./getcpu_example

# 需要 root 权限的测试
sudo ./priority_example
sudo ./rr_interval_example

  1. 系统要求检查
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# 检查内核版本
uname -r

# 检查系统调用支持
grep -E "(pread|pwrite)" /usr/include/asm/unistd_64.h

# 检查 CPU 信息
lscpu

# 检查调度器信息
cat /proc/sched_debug 2>/dev/null || echo "无法读取调度器调试信息"

# 检查实时调度支持
grep -i realtime /boot/config-$(uname -r)

# 检查 NUMA 支持
numactl --hardware 2>/dev/null || echo "系统不支持 NUMA"

  1. 重要注意事项

5.1 权限要求

  • 普通用户: 可以使用 pread/pwrite 等基本 I/O 操作

  • root 用户: 需要设置实时调度策略 (SCHED_FIFO/SCHED_RR)

  • CAP_SYS_NICE: 某些操作需要此能力

5.2 错误处理

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
// 安全的系统调用封装
int safe_pread(int fd, void *buf, size_t count, off_t offset) {
if (fd < 0 || !buf || count == 0) {
errno = EINVAL;
return -1;
}

ssize_t result;
do {
result = pread(fd, buf, count, offset);
} while (result == -1 && errno == EINTR);

return result;
}

// 安全的 CPU 亲和性设置
int safe_sched_setaffinity(pid_t pid, const cpu_set_t *mask) {
if (!mask) {
errno = EINVAL;
return -1;
}

return sched_setaffinity(pid, sizeof(cpu_set_t), mask);
}

5.3 性能考虑

1
2
3
4
5
6
7
8
9
10
11
12
13
// 性能优化建议
void performance_optimization_tips() {
printf("性能优化建议:\n");
printf("1. 批量操作: 使用 preadv/pwritev 减少系统调用次数\n");
printf("2. 缓冲区大小: 合理设置缓冲区大小避免频繁调用\n");
printf("3. CPU 亲和性: 合理绑定 CPU 提高缓存命中率\n");
printf("4. 调度策略: 根据应用特点选择合适的调度策略\n");
printf("5. 优先级设置: 避免过度使用高优先级影响系统稳定性\n");
printf("6. 时间片调整: 根据应用需求调整时间片长度\n");
printf("7. 资源限制: 合理设置进程资源限制\n");
printf("8. 内存管理: 避免内存碎片和频繁分配\n");
}

5.4 最佳实践

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
// 完整的 I/O 操作最佳实践
typedef struct {
int fd;
size_t buffer_size;
int use_positioned_io;
int use_scatter_gather;
cpu_set_t cpu_affinity;
int has_cpu_affinity;
} io_context_t;

// 初始化 I/O 上下文
int init_io_context(io_context_t *ctx, const char *filename) {
ctx->fd = open(filename, O_RDWR | O_CREAT, 0644);
if (ctx->fd == -1) {
return -1;
}

ctx->buffer_size = 4096;
ctx->use_positioned_io = 1;
ctx->use_scatter_gather = 0;
ctx->has_cpu_affinity = 0;

return 0;
}

// 清理 I/O 上下文
void cleanup_io_context(io_context_t *ctx) {
if (ctx->fd != -1) {
close(ctx->fd);
ctx->fd = -1;
}
}

  1. 实际应用场景

6.1 数据库系统

1
2
3
4
5
6
7
// 数据库页 I/O 操作
int db_page_io(int fd, off_t page_offset, void *page_data, size_t page_size) {
// 使用 pread/pwrite 进行页级别的随机访问
ssize_t bytes_read = pread(fd, page_data, page_size, page_offset);
return (bytes_read == (ssize_t)page_size) ? 0 : -1;
}

6.2 实时系统

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 实时应用调度设置
int setup_realtime_scheduling(int priority) {
struct sched_param param;
param.sched_priority = priority;

// 设置实时调度策略
if (sched_setscheduler(0, SCHED_FIFO, &param) == -1) {
return -1;
}

// 设置 CPU 亲和性
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
CPU_SET(0, &cpu_set); // 绑定到 CPU 0

return sched_setaffinity(0, sizeof(cpu_set), &cpu_set);
}

6.3 网络服务器

1
2
3
4
5
6
// 网络服务器 I/O 处理
int handle_network_io(int client_fd, struct iovec *iov, int iovcnt) {
// 使用 preadv/pwritev 处理网络数据包
return pwritev(client_fd, iov, iovcnt, 0);
}

  1. 总结

7.1 核心概念回顾

Linux 调度器函数族为进程调度控制提供了精细化的管理能力:

sched_yield: 让出当前 CPU 时间片,允许同优先级进程运行

sched_getscheduler/sched_setscheduler: 获取和设置进程调度策略

sched_getaffinity/sched_setaffinity: 获取和设置 CPU 亲和性

sched_get_priority_min/sched_get_priority_max: 获取调度策略优先级范围

sched_rr_get_interval: 获取轮转调度时间片长度

sched_getcpu: 获取当前运行的 CPU 编号

prlimit64: 获取和设置进程资源限制

7.2 调度策略详解

五种主要调度策略:

  • SCHED_OTHER: 默认分时调度(CFS),适合普通应用

  • SCHED_FIFO: 实时先进先出,高优先级进程持续运行

  • SCHED_RR: 实时轮转调度,相同优先级进程时间片轮转

  • SCHED_BATCH: 批处理优化,减少上下文切换

  • SCHED_IDLE: 空闲任务,只在系统空闲时运行

7.3 性能优化要点

调度策略选择:

  • 普通应用:使用 SCHED_OTHER(默认)

  • 实时系统:使用 SCHED_FIFO 或 SCHED_RR

  • 批处理任务:使用 SCHED_BATCH

  • 后台任务:使用 SCHED_IDLE

CPU 亲和性优化:

  • 减少 CPU 缓存失效

  • 提高缓存命中率

  • 降低上下文切换开销

  • 改善 NUMA 访问模式

7.4 安全和权限管理

权限要求:

  • 普通用户:可使用 SCHED_OTHER/SCHED_BATCH/SCHED_IDLE

  • root 用户:可使用所有调度策略

  • CAP_SYS_NICE:允许修改调度策略和优先级

  • CAP_SYS_ADMIN:允许使用 prlimit64 设置资源限制

安全考虑:

1
2
3
4
5
6
7
8
9
10
11
// 权限检查示例
int check_scheduling_permissions() {
if (geteuid() == 0) {
return 1; // root 权限
}

// 检查 CAP_SYS_NICE 能力
// 使用 libcap-ng 库进行能力检查
return 0; // 普通权限
}

7.5 实际应用场景

适用场景:

实时系统:音视频处理、工业控制(SCHED_FIFO/SCHED_RR)

高性能计算:科学计算、数据分析(CPU 亲和性绑定)

服务器应用:Web 服务、数据库(合理的调度策略)

系统监控:性能分析、资源管理(sched_getcpu)

容器技术:资源限制、进程隔离(prlimit64)

7.6 最佳实践

调度策略设置:

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
// 安全的调度策略设置
int safe_set_scheduler(pid_t pid, int policy, int priority) {
struct sched_param param;

// 验证参数
if (priority < sched_get_priority_min(policy) ||
priority > sched_get_priority_max(policy)) {
errno = EINVAL;
return -1;
}

param.sched_priority = priority;

// 设置调度策略
int result = sched_setscheduler(pid, policy, &param);

if (result == -1) {
switch (errno) {
case EPERM:
fprintf(stderr, "权限不足,需要适当权限\n");
break;
case EINVAL:
fprintf(stderr, "无效的策略或优先级\n");
break;
case ESRCH:
fprintf(stderr, "进程不存在\n");
break;
}
}

return result;
}

CPU 亲和性管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 智能 CPU 绑定
int smart_cpu_binding(pid_t pid, int cpu_count) {
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);

// 根据系统 CPU 数量智能绑定
int available_cpus = sysconf(_SC_NPROCESSORS_ONLN);
int bind_count = (cpu_count < available_cpus) ? cpu_count : available_cpus;

for (int i = 0; i < bind_count; i++) {
CPU_SET(i, &cpu_set);
}

return sched_setaffinity(pid, sizeof(cpu_set), &cpu_set);
}

资源限制控制:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// 安全的资源限制设置
int safe_set_resource_limit(int resource, rlim_t soft_limit, rlim_t hard_limit) {
struct rlimit64 limit;
limit.rlim_cur = soft_limit;
limit.rlim_max = hard_limit;

int result = prlimit64(0, resource, &limit, NULL);

if (result == -1) {
switch (errno) {
case EPERM:
fprintf(stderr, "权限不足,需要 CAP_SYS_RESOURCE 能力\n");
break;
case EINVAL:
fprintf(stderr, "无效的资源类型或限制值\n");
break;
}
}

return result;
}

7.7 学习建议

掌握路径:

入门阶段:理解基本调度概念和 sched_yield 使用

进阶阶段:掌握调度策略和 CPU 亲和性

高级阶段:精通资源限制和性能优化

专家阶段:实现复杂的调度控制系统

实践要点:

  • 从简单示例开始逐步复杂化

  • 重点关注权限管理和错误处理

  • 实际项目中验证调度效果

  • 持续关注实时系统发展

这些调度器函数是 Linux 系统编程的重要组成部分,正确掌握和使用它们对于开发高性能、实时性要求高的应用程序至关重要。通过系统的学习和实践,开发者可以充分发挥 Linux 调度系统的强大功能。

data-ad-format="auto" data-full-width-responsive="true">