getpriority系统调用及示例

getpriority - 获取进程或进程组的优先级

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

getpriority 是 Linux 系统调用,用于查询进程、进程组或用户的调度优先级。优先级范围 -20(最高)到 +19(最低)。函数原型为 int getpriority(int which, id_t who),参数 which 指定查询类型(PRIO_PROCESS/PRIO_PGRP/PRIO_USER),who 为对应 ID。成功返回优先级值,失败返回 -1 并设置 errno。需注意返回值可能为 -1(成功时),应先清除 errno 再调用。示例代码展示了如何获取当前进程、进程组和用户的优

1. 函数介绍

getpriority 是一个 Linux 系统调用,用于获取指定进程或进程组的调度优先级。它是 Unix/Linux 系统中进程调度管理的重要组成部分,允许程序查询进程的当前优先级设置。

在 Linux 系统中,进程优先级影响 CPU 调度,优先级高的进程会获得更多 CPU 时间。getpriority 与 setpriority 配合使用,提供了完整的优先级管理功能。

2. 函数原型

1
2
3
4
#include <sys/resource.h>

int getpriority(int which, id_t who);

3. 功能

获取指定进程、进程组或用户的所有进程的调度优先级。优先级值范围通常为 -20 到 +19,其中 -20 表示最高优先级,+19 表示最低优先级。

4. 参数

int which: 指定查询的类型

  • PRIO_PROCESS: 查询单个进程的优先级

  • PRIO_PGRP: 查询进程组中所有进程的优先级

  • PRIO_USER: 查询指定用户的所有进程的优先级

id_t who: 根据 which 参数指定的具体 ID

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

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

  • PRIO_USER: 用户 ID(0 表示当前用户)

5. 返回值

  • 成功时:返回优先级值(范围 -20 到 +19)

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

  • 注意:由于成功时可能返回 -1,需要先清除 errno 再调用

6. 常见 errno 错误码

  • ESRCH: 指定的进程、进程组或用户不存在

  • EINVAL: which 参数无效

  • EPERM: 权限不足(无法访问指定进程的信息)

  • EACCES: 访问被拒绝(某些安全策略下)

7. 相似函数,或关联函数

  • setpriority(): 设置进程优先级

  • nice(): 调整当前进程的优先级

  • getrlimit(), setrlimit(): 获取/设置资源限制

  • sched_getparam(), sched_setparam(): 更高级的调度参数管理

  • sched_getscheduler(), sched_setscheduler(): 获取/设置调度策略

  • getrusage(): 获取进程资源使用情况

  • /proc/[pid]/stat: 查看进程状态信息

8. 示例代码

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

int safe_getpriority(int which, id_t who) {
errno = 0; // 必须先清除 errno
int priority = getpriority(which, who);
if (priority == -1 && errno != 0) {
return -1; // 真正的错误
}
return priority;
}

int main() {
int priority;

printf("=== 进程优先级获取 ===\n");

// 获取当前进程的优先级
priority = safe_getpriority(PRIO_PROCESS, 0);
if (priority == -1) {
perror("获取当前进程优先级失败");
} else {
printf("当前进程优先级: %d\n", priority);
}

// 获取当前进程组的优先级
priority = safe_getpriority(PRIO_PGRP, 0);
if (priority == -1) {
perror("获取当前进程组优先级失败");
} else {
printf("当前进程组优先级: %d\n", priority);
}

// 获取当前用户的进程优先级
priority = safe_getpriority(PRIO_USER, 0);
if (priority == -1) {
perror("获取当前用户进程优先级失败");
} else {
printf("当前用户进程优先级: %d\n", priority);
}

// 获取 init 进程的优先级
priority = safe_getpriority(PRIO_PROCESS, 1);
if (priority == -1) {
if (errno == EPERM) {
printf("权限不足,无法获取 init 进程优先级\n");
} else {
perror("获取 init 进程优先级失败");
}
} else {
printf("init 进程优先级: %d\n", priority);
}

return 0;
}

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

void test_getpriority(int which, id_t who, const char *description) {
printf("\n测试 %s:\n", description);

errno = 0; // 清除 errno
int priority = getpriority(which, who);

if (priority == -1 && errno != 0) {
printf(" getpriority 调用失败: %s\n", strerror(errno));
switch (errno) {
case ESRCH:
printf(" 原因: 指定的进程/组/用户不存在\n");
break;
case EINVAL:
printf(" 原因: 无效的 which 参数\n");
break;
case EPERM:
printf(" 原因: 权限不足\n");
break;
default:
printf(" 其他错误\n");
break;
}
} else {
printf(" 优先级: %d\n", priority);
}
}

int main() {
printf("=== getpriority 错误处理测试 ===\n");

// 测试正常情况
test_getpriority(PRIO_PROCESS, 0, "当前进程");
test_getpriority(PRIO_PGRP, 0, "当前进程组");
test_getpriority(PRIO_USER, getuid(), "当前用户");

// 测试无效参数
test_getpriority(999, 0, "无效的 which 参数");

// 测试不存在的进程
test_getpriority(PRIO_PROCESS, 999999, "不存在的进程");

// 测试不存在的进程组
test_getpriority(PRIO_PGRP, 999999, "不存在的进程组");

// 创建子进程进行测试
pid_t child_pid = fork();
if (child_pid == -1) {
perror("fork 失败");
exit(EXIT_FAILURE);
}

if (child_pid == 0) {
// 子进程
printf("\n=== 子进程信息 ===\n");
printf("子进程 ID: %d\n", getpid());
printf("父进程 ID: %d\n", getppid());

// 子进程设置自己的优先级
if (setpriority(PRIO_PROCESS, 0, 10) == 0) {
printf("子进程成功设置优先级为 10\n");
} else {
perror("子进程设置优先级失败");
}

// 显示子进程优先级
errno = 0;
int child_priority = getpriority(PRIO_PROCESS, 0);
if (!(child_priority == -1 && errno != 0)) {
printf("子进程当前优先级: %d\n", child_priority);
}

// 子进程睡眠一段时间
sleep(3);
exit(0);
} else {
// 父进程
printf("\n=== 父进程测试子进程 ===\n");
printf("子进程 ID: %d\n", child_pid);

// 父进程获取子进程优先级
test_getpriority(PRIO_PROCESS, child_pid, "子进程(运行中)");

// 等待子进程结束
int status;
waitpid(child_pid, &status, 0);
printf("子进程已结束\n");

// 再次测试已结束的进程
test_getpriority(PRIO_PROCESS, child_pid, "已结束的子进程");
}

return 0;
}

示例3:优先级监控和管理工具

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

typedef struct {
pid_t pid;
int priority;
char process_name&#91;256];
} process_priority_t;

int safe_getpriority(int which, id_t who) {
errno = 0;
int priority = getpriority(which, who);
if (priority == -1 && errno != 0) {
return -999; // 特殊错误值
}
return priority;
}

void print_priority_info(const char *label, int priority) {
if (priority == -999) {
printf("%s: 无法获取\n", label);
} else {
printf("%s: %d", label, priority);
if (priority < 0) {
printf(" (高优先级)");
} else if (priority > 0) {
printf(" (低优先级)");
} else {
printf(" (正常优先级)");
}
printf("\n");
}
}

void analyze_process_priorities() {
printf("=== 进程优先级分析 ===\n");

// 当前进程信息
printf("当前进程信息:\n");
printf(" PID: %d\n", getpid());
printf(" UID: %d", getuid());
struct passwd *pwd = getpwuid(getuid());
if (pwd) {
printf(" (%s)", pwd->pw_name);
}
printf("\n");

printf(" GID: %d", getgid());
struct group *grp = getgrgid(getgid());
if (grp) {
printf(" (%s)", grp->gr_name);
}
printf("\n");

// 各种优先级信息
int current_priority = safe_getpriority(PRIO_PROCESS, 0);
print_priority_info(" 当前进程优先级", current_priority);

int pgrp_priority = safe_getpriority(PRIO_PGRP, 0);
print_priority_info(" 当前进程组优先级", pgrp_priority);

int user_priority = safe_getpriority(PRIO_USER, getuid());
print_priority_info(" 当前用户进程优先级", user_priority);

// 系统关键进程优先级
printf("\n系统关键进程优先级:\n");

int init_priority = safe_getpriority(PRIO_PROCESS, 1);
print_priority_info(" init 进程 (PID 1)", init_priority);

// 获取 shell 进程优先级
pid_t shell_pid = getppid();
int shell_priority = safe_getpriority(PRIO_PROCESS, shell_pid);
printf(" 父进程 (shell) PID %d", shell_pid);
print_priority_info("", shell_priority);
}

void priority_statistics() {
printf("\n=== 优先级统计信息 ===\n");

// 获取当前用户的进程优先级范围
int min_priority = 20, max_priority = -20;
int sum_priority = 0, count = 0;

// 这里简化处理,实际应用中可能需要扫描 /proc
int current_priority = safe_getpriority(PRIO_PROCESS, 0);
if (current_priority != -999) {
min_priority = max_priority = sum_priority = current_priority;
count = 1;
}

printf("当前会话优先级统计:\n");
printf(" 进程数量: %d\n", count);
if (count > 0) {
printf(" 最低优先级: %d\n", min_priority);
printf(" 最高优先级: %d\n", max_priority);
printf(" 平均优先级: %.2f\n", (double)sum_priority / count);
}
}

int main() {
analyze_process_priorities();
priority_statistics();

// 交互式优先级查询
printf("\n=== 交互式查询 ===\n");
printf("输入进程 ID 查询优先级 (输入 0 退出): ");

pid_t target_pid;
while (scanf("%d", &target_pid) == 1 && target_pid != 0) {
if (target_pid > 0) {
int priority = safe_getpriority(PRIO_PROCESS, target_pid);
if (priority != -999) {
printf("进程 %d 的优先级: %d\n", target_pid, priority);
} else {
printf("无法获取进程 %d 的优先级\n", target_pid);
}
}
printf("继续输入进程 ID (输入 0 退出): ");
}

return 0;
}

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

volatile sig_atomic_t running = 1;

void signal_handler(int sig) {
running = 0;
printf("\n收到信号 %d,停止监控\n", sig);
}

int safe_getpriority(int which, id_t who) {
errno = 0;
int priority = getpriority(which, who);
if (priority == -1 && errno != 0) {
return -999;
}
return priority;
}

void monitor_priority_changes(pid_t target_pid, int duration) {
int last_priority = -999;
time_t start_time = time(NULL);
time_t current_time;

printf("开始监控进程 %d 的优先级变化 (%d 秒)...\n", target_pid, duration);
printf("%-10s %-12s %s\n", "时间", "优先级", "状态");
printf("%-10s %-12s %s\n", "----", "----", "----");

while (running && (current_time = time(NULL)) - start_time < duration) {
int current_priority = safe_getpriority(PRIO_PROCESS, target_pid);

if (current_priority != -999) {
char status&#91;20] = "稳定";

if (last_priority != -999 && current_priority != last_priority) {
snprintf(status, sizeof(status), "变化 %d->%d",
last_priority, current_priority);
}

printf("%-10ld %-12d %s\n",
current_time - start_time,
current_priority,
status);

last_priority = current_priority;
} else {
printf("%-10ld %-12s %s\n",
current_time - start_time,
"无法获取",
"错误");
}

sleep(1);
}
}

void demonstrate_priority_adjustment() {
printf("=== 优先级调整演示 ===\n");

int original_priority = safe_getpriority(PRIO_PROCESS, 0);
printf("原始优先级: %d\n", original_priority);

// 提高优先级(需要权限)
printf("尝试提高优先级到 -5...\n");
if (setpriority(PRIO_PROCESS, 0, -5) == 0) {
int new_priority = safe_getpriority(PRIO_PROCESS, 0);
printf("优先级调整成功: %d\n", new_priority);
} else {
if (errno == EPERM) {
printf("权限不足,无法提高优先级(需要 root 权限)\n");
} else {
perror("优先级调整失败");
}
}

// 降低优先级
printf("尝试降低优先级到 10...\n");
if (setpriority(PRIO_PROCESS, 0, 10) == 0) {
int new_priority = safe_getpriority(PRIO_PROCESS, 0);
printf("优先级调整成功: %d\n", new_priority);
} else {
perror("优先级调整失败");
}

// 恢复原始优先级
if (original_priority != -999) {
if (setpriority(PRIO_PROCESS, 0, original_priority) == 0) {
printf("已恢复原始优先级: %d\n",
safe_getpriority(PRIO_PROCESS, 0));
}
}
}

int main() {
signal(SIGINT, signal_handler);
signal(SIGTERM, signal_handler);

demonstrate_priority_adjustment();

printf("\n当前进程优先级: %d\n", safe_getpriority(PRIO_PROCESS, 0));

// 如果需要,可以监控优先级变化
char choice;
printf("\n是否监控当前进程优先级变化? (y/N): ");
getchar(); // 清除缓冲区
if (scanf("%c", &choice) == 1 && (choice == 'y' || choice == 'Y')) {
monitor_priority_changes(getpid(), 10);
}

return 0;
}

9. 优先级值说明

Linux 进程优先级系统:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 优先级范围:-20 到 +19
// -20: 最高优先级
// 0: 默认优先级
// +19: 最低优先级

// 特殊优先级值
#define PRIO_MIN -20
#define PRIO_MAX 19

// 优先级类别
-20 to -1: 高优先级进程
0: 正常优先级进程
+1 to +19: 低优先级进程

10. 实际应用场景

场景1:系统监控工具

1
2
3
4
5
int is_high_priority_process(pid_t pid) {
int priority = safe_getpriority(PRIO_PROCESS, pid);
return (priority != -999 && priority < 0);
}

场景2:资源管理

1
2
3
4
5
void adjust_batch_job_priority() {
// 批处理作业使用较低优先级
setpriority(PRIO_PROCESS, 0, 15);
}

场景3:性能优化

1
2
3
4
5
void optimize_critical_process() {
// 关键进程使用较高优先级
setpriority(PRIO_PROCESS, 0, -5);
}

11. 注意事项

使用 getpriority 时的重要注意事项:

返回值检查: 必须先清除 errno,因为成功时可能返回 -1

权限问题: 访问其他进程信息可能需要适当权限

进程生命周期: 进程结束后相关信息可能不可用

实时性: 优先级可能在查询期间发生变化

系统限制: 某些优先级值可能需要特殊权限才能设置

12. 优先级与调度策略

1
2
3
4
5
6
7
8
9
10
// 不同调度策略的优先级处理
void explain_scheduling_policies() {
printf("Linux 调度策略优先级说明:\n");
printf("1. SCHED_FIFO: 实时优先级 1-99\n");
printf("2. SCHED_RR: 实时优先级 1-99\n");
printf("3. SCHED_OTHER: 静态优先级 -20 到 +19\n");
printf("4. SCHED_BATCH: 批处理优化\n");
printf("5. SCHED_IDLE: 空闲任务\n");
}

总结

getpriority 是进程优先级管理的重要函数,关键要点:

优先级查询: 获取进程、进程组或用户的调度优先级

错误处理: 特殊的返回值处理机制(需要清除 errno)

权限控制: 访问其他进程信息需要适当权限

系统管理: 在系统监控和资源管理中广泛使用

性能优化: 帮助识别和调整关键进程的优先级

正确使用 getpriority 可以帮助程序了解当前的调度状态,实现更精细的性能管理和资源控制。

getpriority系统调用及示例-CSDN博客

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