81. getpriority - 获取进程或进程组的优先级 見出しへのリンク
1. 函数介绍 見出しへのリンク
getpriority
是一个 Linux 系统调用,用于获取指定进程或进程组的调度优先级。它是 Unix/Linux 系统中进程调度管理的重要组成部分,允许程序查询进程的当前优先级设置。
在 Linux 系统中,进程优先级影响 CPU 调度,优先级高的进程会获得更多 CPU 时间。getpriority
与 setpriority
配合使用,提供了完整的优先级管理功能。
2. 函数原型 見出しへのリンク
#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
参数指定的具体 IDPRIO_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:基本使用 - 获取进程优先级 見出しへのリンク
#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:错误处理和特殊情况 見出しへのリンク
#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:优先级监控和管理工具 見出しへのリンク
#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[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:优先级调整和监控 見出しへのリンク
#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[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 进程优先级系统:
// 优先级范围:-20 到 +19
// -20: 最高优先级
// 0: 默认优先级
// +19: 最低优先级
// 特殊优先级值
#define PRIO_MIN -20
#define PRIO_MAX 19
// 优先级类别
-20 to -1: 高优先级进程
0: 正常优先级进程
+1 to +19: 低优先级进程
10. 实际应用场景 見出しへのリンク
场景1:系统监控工具 見出しへのリンク
int is_high_priority_process(pid_t pid) {
int priority = safe_getpriority(PRIO_PROCESS, pid);
return (priority != -999 && priority < 0);
}
场景2:资源管理 見出しへのリンク
void adjust_batch_job_priority() {
// 批处理作业使用较低优先级
setpriority(PRIO_PROCESS, 0, 15);
}
场景3:性能优化 見出しへのリンク
void optimize_critical_process() {
// 关键进程使用较高优先级
setpriority(PRIO_PROCESS, 0, -5);
}
11. 注意事项 見出しへのリンク
使用 getpriority
时的重要注意事项:
- 返回值检查: 必须先清除
errno
,因为成功时可能返回 -1 - 权限问题: 访问其他进程信息可能需要适当权限
- 进程生命周期: 进程结束后相关信息可能不可用
- 实时性: 优先级可能在查询期间发生变化
- 系统限制: 某些优先级值可能需要特殊权限才能设置
12. 优先级与调度策略 見出しへのリンク
// 不同调度策略的优先级处理
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
可以帮助程序了解当前的调度状态,实现更精细的性能管理和资源控制。