setpriority系统调用及示例

setpriority 函数详解

1. 函数介绍

setpriority 是Linux系统调用,用于设置进程、进程组或用户的调度优先级(nice值)。它允许调整进程的CPU调度优先级,从而影响进程获得CPU时间的相对比例。较低的nice值表示更高的优先级,较高的nice值表示更低的优先级。

2. 函数原型

#include <sys/resource.h>
int setpriority(int which, id_t who, int prio);

3. 功能

setpriority 设置指定进程、进程组或用户的调度优先级(nice值)。这个函数主要用于进程调度优化,通过调整优先级来平衡系统资源分配。

4. 参数

  • int which: 指定操作类型(PRIO_PROCESS, PRIO_PGRP, PRIO_USER)
  • id_t who: 根据which参数指定的ID(进程ID、进程组ID或用户ID)
  • int prio: 新的优先级值(nice值,范围-20到19)

5. 返回值

  • 成功: 返回0
  • 失败: 返回-1,并设置errno

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

  • getpriority: 获取优先级
  • nice: 调整当前进程的nice值
  • sched_setscheduler: 设置进程调度策略
  • sched_setparam: 设置进程调度参数

7. 示例代码

示例1:基础setpriority使用

#include <sys/resource.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>

/**
 * 显示进程优先级信息
 */
void show_process_priority() {
    pid_t pid = getpid();
    uid_t uid = getuid();
    int prio;
    
    printf("=== 进程优先级信息 ===\n");
    printf("进程ID: %d\n", pid);
    printf("用户ID: %d\n", uid);
    
    // 获取当前进程优先级
    errno = 0;
    prio = getpriority(PRIO_PROCESS, 0);
    if (prio == -1 && errno != 0) {
        printf("获取进程优先级失败: %s\n", strerror(errno));
    } else {
        printf("当前进程优先级 (nice值): %d\n", prio);
    }
    
    printf("\n");
}

/**
 * 演示基础setpriority使用方法
 */
int demo_setpriority_basic() {
    int original_prio, new_prio;
    int result;
    
    printf("=== 基础setpriority使用示例 ===\n");
    
    // 显示原始优先级信息
    show_process_priority();
    original_prio = getpriority(PRIO_PROCESS, 0);
    printf("原始优先级: %d\n", original_prio);
    
    // 提高进程优先级(降低nice值)
    printf("1. 提高进程优先级 (nice值从 %d 降到 %d):\n", original_prio, original_prio - 5);
    result = setpriority(PRIO_PROCESS, 0, original_prio - 5);
    
    if (result == 0) {
        printf("   ✓ 成功提高优先级\n");
        
        // 验证设置结果
        new_prio = getpriority(PRIO_PROCESS, 0);
        printf("   新优先级: %d\n", new_prio);
        
        if (new_prio == original_prio - 5) {
            printf("   ✓ 优先级设置正确\n");
        } else {
            printf("   ✗ 优先级设置可能有问题\n");
        }
    } else {
        printf("   ✗ 提高优先级失败: %s\n", strerror(errno));
        if (errno == EACCES) {
            printf("   原因:需要root权限或CAP_SYS_NICE能力来提高优先级\n");
        } else if (errno == EINVAL) {
            printf("   原因:优先级值超出有效范围\n");
        } else if (errno == ESRCH) {
            printf("   原因:指定的进程不存在\n");
        }
    }
    
    // 降低进程优先级(提高nice值)
    printf("\n2. 降低进程优先级 (nice值从 %d 升到 %d):\n", new_prio, new_prio + 10);
    result = setpriority(PRIO_PROCESS, 0, new_prio + 10);
    
    if (result == 0) {
        printf("   ✓ 成功降低优先级\n");
        
        // 验证设置结果
        new_prio = getpriority(PRIO_PROCESS, 0);
        printf("   新优先级: %d\n", new_prio);
    } else {
        printf("   ✗ 降低优先级失败: %s\n", strerror(errno));
    }
    
    // 恢复原始优先级
    printf("\n3. 恢复原始优先级 (%d):\n", original_prio);
    result = setpriority(PRIO_PROCESS, 0, original_prio);
    
    if (result == 0) {
        printf("   ✓ 成功恢复原始优先级\n");
        new_prio = getpriority(PRIO_PROCESS, 0);
        printf("   最终优先级: %d\n", new_prio);
    } else {
        printf("   ✗ 恢复原始优先级失败: %s\n", strerror(errno));
    }
    
    return 0;
}

int main() {
    return demo_setpriority_basic();
}

示例2:多进程优先级管理

#include <sys/resource.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#include <signal.h>

/**
 * 工作进程函数
 */
void worker_process(int worker_id, int priority) {
    pid_t pid = getpid();
    
    printf("工作进程 %d 启动 (PID: %d)\n", worker_id, pid);
    
    // 设置进程优先级
    if (setpriority(PRIO_PROCESS, 0, priority) == 0) {
        printf("工作进程 %d 优先级设置为 %d\n", worker_id, priority);
    } else {
        printf("工作进程 %d 优先级设置失败: %s\n", worker_id, strerror(errno));
    }
    
    // 显示当前优先级
    int current_prio = getpriority(PRIO_PROCESS, 0);
    printf("工作进程 %d 当前优先级: %d\n", worker_id, current_prio);
    
    // 模拟工作负载
    volatile long sum = 0;
    for (long i = 0; i < 1000000000L; i++) {
        sum += i;
        if (i % 100000000 == 0) {
            printf("工作进程 %d: 进度 %ld%%\n", worker_id, i / 10000000);
        }
    }
    
    printf("工作进程 %d 完成,计算结果: %ld\n", worker_id, sum);
    exit(0);
}

/**
 * 演示多进程优先级管理
 */
int demo_multiprocess_priority() {
    pid_t workers[3];
    int priorities[] = {-5, 0, 10};  // 高、中、低优先级
    int worker_count = 3;
    
    printf("=== 多进程优先级管理演示 ===\n");
    
    // 显示父进程信息
    printf("父进程信息:\n");
    printf("  进程ID: %d\n", getpid());
    printf("  当前优先级: %d\n", getpriority(PRIO_PROCESS, 0));
    printf("\n");
    
    // 创建工作进程
    printf("创建 %d 个工作进程:\n", worker_count);
    for (int i = 0; i < worker_count; i++) {
        workers[i] = fork();
        if (workers[i] == 0) {
            // 子进程
            worker_process(i + 1, priorities[i]);
        } else if (workers[i] > 0) {
            // 父进程
            printf("  创建工作进程 %d: PID=%d, 优先级=%d\n", 
                   i + 1, workers[i], priorities[i]);
        } else {
            perror("创建工作进程失败");
            // 清理已创建的进程
            for (int j = 0; j < i; j++) {
                kill(workers[j], SIGKILL);
            }
            return -1;
        }
    }
    
    // 显示所有进程的优先级
    printf("\n所有进程优先级信息:\n");
    for (int i = 0; i < worker_count; i++) {
        errno = 0;
        int prio = getpriority(PRIO_PROCESS, workers[i]);
        if (prio != -1 || errno == 0) {
            printf("  进程 %d (PID=%d): 优先级=%d\n", i + 1, workers[i], prio);
        } else {
            printf("  进程 %d (PID=%d): 无法获取优先级 (%s)\n", 
                   i + 1, workers[i], strerror(errno));
        }
    }
    
    // 等待所有工作进程完成
    printf("\n等待工作进程完成:\n");
    int status;
    pid_t finished_pid;
    int finished_count = 0;
    
    while (finished_count < worker_count) {
        finished_pid = wait(&status);
        if (finished_pid > 0) {
            finished_count++;
            printf("  工作进程 (PID=%d) 已完成,退出状态: %d\n", 
                   finished_pid, WEXITSTATUS(status));
        } else {
            break;
        }
    }
    
    printf("所有工作进程已完成\n");
    return 0;
}

int main() {
    return demo_multiprocess_priority();
}

示例3:进程组优先级设置

#include <sys/resource.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#include <signal.h>

/**
 * 显示进程组信息
 */
void show_process_group_info(pid_t pgid) {
    printf("进程组 %d 信息:\n", pgid);
    
    // 显示进程组中所有进程的优先级
    // 注意:这里简化处理,实际应用中需要遍历/proc或使用其他方法
    int current_prio = getpriority(PRIO_PGRP, pgid);
    if (current_prio != -1 || errno == 0) {
        printf("  进程组优先级: %d\n", current_prio);
    } else {
        printf("  无法获取进程组优先级: %s\n", strerror(errno));
    }
}

/**
 * 工作进程函数(进程组成员)
 */
void group_worker(int worker_id, pid_t group_leader) {
    pid_t pid = getpid();
    
    printf("组工作进程 %d 启动 (PID: %d)\n", worker_id, pid);
    
    // 加入指定的进程组
    if (setpgid(0, group_leader) == 0) {
        printf("组工作进程 %d 成功加入进程组 %d\n", worker_id, group_leader);
    } else {
        printf("组工作进程 %d 加入进程组失败: %s\n", worker_id, strerror(errno));
    }
    
    // 显示当前进程信息
    printf("组工作进程 %d 当前优先级: %d\n", worker_id, getpriority(PRIO_PROCESS, 0));
    printf("组工作进程 %d 所属进程组: %d\n", worker_id, getpgid(0));
    
    // 模拟工作
    for (int i = 0; i < 10; i++) {
        printf("组工作进程 %d 工作中... (%d/10)\n", worker_id, i + 1);
        sleep(1);
    }
    
    printf("组工作进程 %d 完成\n", worker_id);
    exit(0);
}

/**
 * 演示进程组优先级设置
 */
int demo_process_group_priority() {
    pid_t group_leader_pid;
    pid_t workers[2];
    pid_t group_id;
    
    printf("=== 进程组优先级设置演示 ===\n");
    
    // 创建进程组领导进程
    group_leader_pid = fork();
    if (group_leader_pid == 0) {
        // 进程组领导进程
        printf("进程组领导进程启动 (PID: %d)\n", getpid());
        
        // 创建自己的进程组
        if (setpgid(0, 0) == 0) {
            group_id = getpid();
            printf("成功创建进程组: %d\n", group_id);
        } else {
            printf("创建进程组失败: %s\n", strerror(errno));
            exit(1);
        }
        
        // 显示初始优先级
        printf("进程组领导进程初始优先级: %d\n", getpriority(PRIO_PROCESS, 0));
        
        // 创建组内工作进程
        for (int i = 0; i < 2; i++) {
            workers[i] = fork();
            if (workers[i] == 0) {
                group_worker(i + 1, group_id);
            } else if (workers[i] > 0) {
                printf("创建组工作进程 %d: PID=%d\n", i + 1, workers[i]);
            }
        }
        
        // 等待子进程启动
        sleep(1);
        
        // 设置整个进程组的优先级
        printf("\n设置进程组 %d 的优先级:\n", group_id);
        show_process_group_info(group_id);
        
        // 尝试设置进程组优先级
        printf("尝试将进程组 %d 的优先级设置为 5:\n", group_id);
        int result = setpriority(PRIO_PGRP, group_id, 5);
        if (result == 0) {
            printf("✓ 成功设置进程组优先级\n");
        } else {
            printf("✗ 设置进程组优先级失败: %s\n", strerror(errno));
            if (errno == EACCES) {
                printf("  需要适当权限来设置优先级\n");
            }
        }
        
        // 验证设置结果
        show_process_group_info(group_id);
        
        // 等待组内工作进程完成
        for (int i = 0; i < 2; i++) {
            int status;
            waitpid(workers[i], &status, 0);
            printf("组工作进程 %d 已完成\n", i + 1);
        }
        
        printf("进程组领导进程结束\n");
        exit(0);
    } else if (group_leader_pid > 0) {
        printf("主进程创建进程组领导进程: %d\n", group_leader_pid);
        
        // 等待进程组领导进程完成
        int status;
        waitpid(group_leader_pid, &status, 0);
        printf("进程组领导进程已结束\n");
    } else {
        perror("创建进程组领导进程失败");
        return -1;
    }
    
    return 0;
}

int main() {
    return demo_process_group_priority();
}

示例4:用户优先级管理

#include <sys/resource.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <pwd.h>

/**
 * 显示用户优先级信息
 */
void show_user_priority(uid_t uid) {
    struct passwd *pwd = getpwuid(uid);
    if (pwd) {
        printf("用户 %s (UID: %d) 信息:\n", pwd->pw_name, uid);
    } else {
        printf("用户 (UID: %d) 信息:\n", uid);
    }
    
    // 获取用户进程的优先级(注意:这会返回其中一个进程的优先级)
    errno = 0;
    int prio = getpriority(PRIO_USER, uid);
    if (prio != -1 || errno == 0) {
        printf("  用户进程优先级: %d\n", prio);
    } else {
        printf("  无法获取用户优先级: %s\n", strerror(errno));
        if (errno == ESRCH) {
            printf("  该用户可能没有运行中的进程\n");
        }
    }
}

/**
 * 演示用户优先级管理
 */
int demo_user_priority_management() {
    uid_t current_uid = getuid();
    uid_t effective_uid = geteuid();
    
    printf("=== 用户优先级管理演示 ===\n");
    
    // 显示当前用户信息
    printf("1. 当前用户信息:\n");
    printf("   真实用户ID: %d\n", current_uid);
    printf("   有效用户ID: %d\n", effective_uid);
    
    show_user_priority(current_uid);
    
    // 检查权限
    printf("\n2. 权限检查:\n");
    if (current_uid == 0 || effective_uid == 0) {
        printf("   ✓ 当前具有root权限\n");
    } else {
        printf("   ✗ 当前没有root权限\n");
        printf("   设置其他用户优先级需要root权限\n");
    }
    
    // 尝试设置当前用户优先级
    printf("\n3. 设置当前用户优先级:\n");
    int original_prio = getpriority(PRIO_USER, current_uid);
    if (original_prio == -1 && errno != 0) {
        original_prio = 0;  // 默认值
    }
    
    printf("   当前用户优先级: %d\n", original_prio);
    printf("   尝试设置为: %d\n", original_prio + 2);
    
    int result = setpriority(PRIO_USER, current_uid, original_prio + 2);
    if (result == 0) {
        printf("   ✓ 成功设置用户优先级\n");
        
        // 验证设置结果
        int new_prio = getpriority(PRIO_USER, current_uid);
        printf("   新用户优先级: %d\n", new_prio);
    } else {
        printf("   ✗ 设置用户优先级失败: %s\n", strerror(errno));
        if (errno == EACCES) {
            printf("   需要root权限来设置用户优先级\n");
        } else if (errno == EPERM) {
            printf("   权限不足\n");
        }
    }
    
    // 显示系统中其他用户(如果有权限)
    printf("\n4. 系统用户优先级信息:\n");
    struct passwd *pwd;
    int user_count = 0;
    
    // 重置密码文件指针
    setpwent();
    
    while ((pwd = getpwent()) != NULL && user_count < 5) {
        // 只显示一些系统用户
        if (pwd->pw_uid < 1000) {  // 系统用户通常UID较小
            show_user_priority(pwd->pw_uid);
            user_count++;
        }
    }
    
    endpwent();
    
    // 恢复原始优先级
    printf("\n5. 恢复原始优先级:\n");
    result = setpriority(PRIO_USER, current_uid, original_prio);
    if (result == 0) {
        printf("   ✓ 成功恢复原始优先级\n");
    } else {
        printf("   ✗ 恢复原始优先级失败: %s\n", strerror(errno));
    }
    
    return 0;
}

int main() {
    return demo_user_priority_management();
}

示例5:优先级调度演示

#include <sys/resource.h>
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#include <time.h>

/**
 * CPU密集型工作函数
 */
void cpu_intensive_work(int worker_id, int priority, int duration_seconds) {
    pid_t pid = getpid();
    clock_t start_time = clock();
    clock_t work_duration = duration_seconds * CLOCKS_PER_SEC;
    
    printf("CPU密集型工作进程 %d 启动 (PID: %d, 优先级: %d)\n", 
           worker_id, pid, priority);
    
    // 设置进程优先级
    if (setpriority(PRIO_PROCESS, 0, priority) != 0) {
        printf("工作进程 %d 设置优先级失败: %s\n", worker_id, strerror(errno));
    }
    
    // 执行CPU密集型工作
    volatile long sum = 0;
    long iterations = 0;
    
    while ((clock() - start_time) < work_duration) {
        sum += iterations;
        iterations++;
        
        // 定期报告进度
        if (iterations % 10000000 == 0) {
            double elapsed = (double)(clock() - start_time) / CLOCKS_PER_SEC;
            printf("工作进程 %d: 迭代 %ld 次, 耗时 %.2f 秒\n", 
                   worker_id, iterations, elapsed);
        }
    }
    
    double total_time = (double)(clock() - start_time) / CLOCKS_PER_SEC;
    printf("工作进程 %d 完成:\n", worker_id);
    printf("  总迭代次数: %ld\n", iterations);
    printf("  总耗时: %.2f 秒\n", total_time);
    printf("  平均迭代速度: %.0f 次/秒\n", iterations / total_time);
    
    exit(0);
}

/**
 * 演示优先级调度效果
 */
int demo_priority_scheduling() {
    pid_t workers[3];
    int priorities[] = {-10, 0, 10};  // 高、中、低优先级
    const char *priority_names[] = {"高优先级", "中优先级", "低优先级"};
    int worker_count = 3;
    int work_duration = 10;  // 工作10秒
    
    printf("=== 优先级调度效果演示 ===\n");
    printf("工作时长: %d 秒\n", work_duration);
    printf("优先级设置: 高(-10), 中(0), 低(10)\n\n");
    
    // 检查权限
    uid_t uid = getuid();
    printf("权限检查:\n");
    if (uid == 0) {
        printf("  ✓ 具有root权限,可以设置所有优先级\n");
    } else {
        printf("  ✗ 没有root权限,可能无法设置负优先级\n");
    }
    printf("\n");
    
    // 创建工作进程
    printf("创建 %d 个工作进程:\n", worker_count);
    for (int i = 0; i < worker_count; i++) {
        workers[i] = fork();
        if (workers[i] == 0) {
            // 子进程
            cpu_intensive_work(i + 1, priorities[i], work_duration);
        } else if (workers[i] > 0) {
            // 父进程
            printf("  %s工作进程 %d: PID=%d, 优先级=%d\n", 
                   priority_names[i], i + 1, workers[i], priorities[i]);
        } else {
            perror("创建工作进程失败");
            // 清理已创建的进程
            for (int j = 0; j < i; j++) {
                kill(workers[j], SIGKILL);
            }
            return -1;
        }
    }
    
    // 显示所有进程的初始优先级
    printf("\n所有进程初始优先级:\n");
    for (int i = 0; i < worker_count; i++) {
        errno = 0;
        int prio = getpriority(PRIO_PROCESS, workers[i]);
        if (prio != -1 || errno == 0) {
            printf("  进程 %d (PID=%d): 优先级=%d\n", i + 1, workers[i], prio);
        } else {
            printf("  进程 %d (PID=%d): 获取优先级失败 (%s)\n", 
                   i + 1, workers[i], strerror(errno));
        }
    }
    
    // 等待所有工作进程完成
    printf("\n等待工作进程完成 (约 %d 秒):\n", work_duration);
    int status;
    pid_t finished_pid;
    int finished_count = 0;
    time_t start_wait = time(NULL);
    
    while (finished_count < worker_count) {
        finished_pid = wait(&status);
        if (finished_pid > 0) {
            finished_count++;
            time_t elapsed = time(NULL) - start_wait;
            printf("  工作进程 (PID=%d) 已完成,耗时 %ld 秒,退出状态: %d\n", 
                   finished_pid, elapsed, WEXITSTATUS(status));
        } else if (finished_pid == -1) {
            if (errno == EINTR) {
                continue;  // 被信号中断,继续等待
            } else {
                break;
            }
        }
    }
    
    // 分析调度效果
    printf("\n=== 调度效果分析 ===\n");
    printf("高优先级进程应该获得更多的CPU时间\n");
    printf("低优先级进程应该获得较少的CPU时间\n");
    printf("实际效果取决于系统负载和调度器实现\n");
    
    // 显示优先级相关建议
    printf("\n=== 优先级使用建议 ===\n");
    printf("1. 优先级范围: -20 (最高) 到 19 (最低)\n");
    printf("2. root权限可以设置负优先级\n");
    printf("3. 普通用户只能设置0到19的优先级\n");
    printf("4. 过高的优先级可能影响系统稳定性\n");
    printf("5. 合理使用优先级平衡系统资源\n");
    
    return 0;
}

int main() {
    return demo_priority_scheduling();
}

setpriority 使用注意事项

系统要求:

  1. 内核版本: 支持进程优先级管理的Linux内核
  2. 权限要求: 设置负优先级需要root权限或CAP_SYS_NICE能力
  3. 架构支持: 支持所有主流架构

优先级范围:

  1. 有效范围: -20 到 19
  2. 默认值: 通常为0
  3. 负值: 更高优先级(需要特权)
  4. 正值: 更低优先级(普通用户可设置)

which参数类型:

  1. PRIO_PROCESS: 指定进程
  2. PRIO_PGRP: 指定进程组
  3. PRIO_USER: 指定用户

错误处理:

  1. EACCES: 权限不足(设置负优先级时)
  2. EINVAL: 优先级值超出有效范围
  3. EPERM: 权限不足
  4. ESRCH: 指定的进程/进程组/用户不存在

性能考虑:

  1. 调度开销: 频繁改变优先级有性能开销
  2. 系统影响: 不当的优先级设置可能影响系统稳定性
  3. 公平性: 避免过度偏向某些进程

安全考虑:

  1. 权限提升: 不当使用可能导致权限提升
  2. 系统稳定性: 过高的优先级可能影响系统响应
  3. 资源竞争: 合理分配优先级避免资源竞争

最佳实践:

  1. 权限检查: 执行前检查是否具有足够权限
  2. 范围验证: 确保优先级值在有效范围内
  3. 错误处理: 妥善处理各种错误情况
  4. 适度使用: 避免过度调整优先级
  5. 监控效果: 监控优先级调整的效果

优先级值说明

Nice值范围:

  • -20: 最高优先级
  • -10: 高优先级
  • 0: 默认优先级
  • 10: 低优先级
  • 19: 最低优先级

权限要求:

// 普通用户可以设置的范围
if (prio >= 0 && prio <= 19) {
    // 可以设置
}

// 设置负优先级需要特权
if (prio < 0) {
    // 需要root权限或CAP_SYS_NICE能力
}

相关系统调用

1. getpriority:

int getpriority(int which, id_t who);

2. nice:

int nice(int inc);

3. sched_setscheduler:

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

常见使用场景

1. 系统服务管理:

// 降低后台服务优先级
setpriority(PRIO_PROCESS, service_pid, 10);

2. 批处理作业:

// 为批处理作业设置较低优先级
setpriority(PRIO_PROCESS, batch_pid, 15);

3. 实时应用:

// 提高关键应用优先级(需要root权限)
setpriority(PRIO_PROCESS, critical_pid, -5);

优先级调度策略

1. 时间片分配:

  • 高优先级进程获得更多CPU时间片
  • 低优先级进程获得较少CPU时间片

2. 调度顺序:

  • 优先调度高优先级进程
  • 低优先级进程可能被延迟执行

3. I/O优先级:

  • 优先级也影响I/O调度
  • 高优先级进程获得更好的I/O性能

总结

setpriority 是Linux系统中重要的进程调度管理函数,提供了:

  1. 优先级控制: 灵活的进程优先级管理
  2. 多级调度: 支持进程、进程组、用户级别的优先级设置
  3. 权限管理: 通过权限控制保证系统安全
  4. 性能优化: 帮助优化系统资源分配

通过合理使用 setpriority,可以构建更加高效和可控的多进程应用程序。在实际应用中,需要注意权限要求、错误处理和系统稳定性等关键问题。

此条目发表在linux文章分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注