Linux 调度器函数sched_*系统调用及示例

Linux 调度器函数详解

1. 概述

sched_* 函数族是 Linux 系统中用于进程调度控制的一系列系统调用。可以把调度器想象成"CPU 时间片的分配管理员"------它决定哪个进程什么时候获得 CPU 时间,就像交通警察决定哪辆车什么时候可以通过路口一样。
这些函数提供了对进程调度策略、优先级、CPU 亲和性等方面的精细控制,是实现高性能、实时应用的重要工具。

2. 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 编号

3. 调度策略详解

3.1 调度策略类型

策略 说明
SCHED_OTHER 0 默认分时调度策略(CFS)
SCHED_FIFO 1 先进先出实时调度策略
SCHED_RR 2 轮转实时调度策略
SCHED_BATCH 3 批处理调度策略
SCHED_IDLE 5 空闲调度策略
SCHED_DEADLINE 6 截止时间调度策略

3.2 调度策略特点

c 复制代码
#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");
}

4. 函数详细介绍

4.1 sched_yield - 让出 CPU 时间片

函数原型
c 复制代码
#include <sched.h>
int sched_yield(void);
功能

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

参数

无参数

返回值
  • 成功: 返回 0
  • 失败: 返回 -1(实际上很少失败)
示例代码
c 复制代码
#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 - 调度策略控制

函数原型
c 复制代码
#include <sched.h>

int sched_getscheduler(pid_t pid);
int sched_setscheduler(pid_t pid, int policy, const struct sched_param *param);
sched_param 结构体
c 复制代码
struct sched_param {
    int sched_priority;  // 调度优先级
    // 对于 SCHED_DEADLINE,还有额外字段
};
功能
  • sched_getscheduler: 获取指定进程的调度策略
  • sched_setscheduler: 设置指定进程的调度策略和参数
参数
  • pid: 进程 ID(0 表示当前进程)
  • policy: 调度策略
  • param: 指向调度参数的指针
返回值
  • sched_getscheduler: 成功返回调度策略,失败返回 -1
  • sched_setscheduler: 成功返回 0,失败返回 -1
示例代码
c 复制代码
#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[] = {SCHED_OTHER, SCHED_FIFO, SCHED_RR, SCHED_BATCH, SCHED_IDLE};
    int num_policies = sizeof(policies) / sizeof(policies[0]);
    
    for (int i = 0; i < num_policies; i++) {
        int min_priority = sched_get_priority_min(policies[i]);
        int max_priority = sched_get_priority_max(policies[i]);
        
        printf("%-20s: 最小优先级 %3d, 最大优先级 %3d\n", 
               policy_to_string(policies[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 亲和性控制

函数原型
c 复制代码
#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 集合操作宏
c 复制代码
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
示例代码
c 复制代码
#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[i]);
        CPU_SET(cpu_list[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[] = {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[] = {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 - 优先级范围查询

函数原型
c 复制代码
#include <sched.h>

int sched_get_priority_min(int policy);
int sched_get_priority_max(int policy);
功能

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

参数
  • policy: 调度策略
返回值
  • 成功: 返回对应的优先级值
  • 失败: 返回 -1,并设置相应的 errno
示例代码
c 复制代码
#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[] = {
        {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[i].name; i++) {
        show_policy_priority_range(policies[i].policy, policies[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 - 轮转调度时间片

函数原型
c 复制代码
#include <sched.h>

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

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

参数
  • pid: 进程 ID(0 表示当前进程)
  • tp: 指向 timespec 结构体的指针,用于存储时间片长度
返回值
  • 成功: 返回 0
  • 失败: 返回 -1,并设置相应的 errno
示例代码
c 复制代码
#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[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 编号

函数原型
c 复制代码
#define _GNU_SOURCE
#include <sched.h>

int sched_getcpu(void);
功能

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

参数

无参数

返回值
  • 成功: 返回 CPU 编号(从 0 开始)
  • 失败: 返回 -1,并设置相应的 errno
示例代码
c 复制代码
#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[4];
    int thread_ids[4] = {1, 2, 3, 4};
    
    printf("创建 4 个线程进行 CPU 绑定测试:\n");
    
    for (int i = 0; i < 4; i++) {
        if (pthread_create(&threads[i], NULL, thread_cpu_info, &thread_ids[i]) != 0) {
            perror("创建线程失败");
            return;
        }
    }
    
    // 等待所有线程完成
    for (int i = 0; i < 4; i++) {
        pthread_join(threads[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;
}

3. 编译和运行说明

bash 复制代码
# 编译所有示例程序
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

4. 系统要求检查

bash 复制代码
# 检查内核版本
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"

5. 重要注意事项

5.1 权限要求

  • 普通用户 : 可以使用 pread/pwrite 等基本 I/O 操作
  • root 用户 : 需要设置实时调度策略 (SCHED_FIFO/SCHED_RR)
  • CAP_SYS_NICE: 某些操作需要此能力

5.2 错误处理

c 复制代码
// 安全的系统调用封装
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 性能考虑

c 复制代码
// 性能优化建议
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 最佳实践

c 复制代码
// 完整的 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;
    }
}

6. 实际应用场景

6.1 数据库系统

c 复制代码
// 数据库页 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 实时系统

c 复制代码
// 实时应用调度设置
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 网络服务器

c 复制代码
// 网络服务器 I/O 处理
int handle_network_io(int client_fd, struct iovec *iov, int iovcnt) {
    // 使用 preadv/pwritev 处理网络数据包
    return pwritev(client_fd, iov, iovcnt, 0);
}

7. 总结

7.1 核心概念回顾

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

  1. sched_yield: 让出当前 CPU 时间片,允许同优先级进程运行
  2. sched_getscheduler/sched_setscheduler: 获取和设置进程调度策略
  3. sched_getaffinity/sched_setaffinity: 获取和设置 CPU 亲和性
  4. sched_get_priority_min/sched_get_priority_max: 获取调度策略优先级范围
  5. sched_rr_get_interval: 获取轮转调度时间片长度
  6. sched_getcpu: 获取当前运行的 CPU 编号
  7. 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 设置资源限制

安全考虑

c 复制代码
// 权限检查示例
int check_scheduling_permissions() {
    if (geteuid() == 0) {
        return 1;  // root 权限
    }
    
    // 检查 CAP_SYS_NICE 能力
    // 使用 libcap-ng 库进行能力检查
    return 0;  // 普通权限
}

7.5 实际应用场景

适用场景

  1. 实时系统:音视频处理、工业控制(SCHED_FIFO/SCHED_RR)
  2. 高性能计算:科学计算、数据分析(CPU 亲和性绑定)
  3. 服务器应用:Web 服务、数据库(合理的调度策略)
  4. 系统监控:性能分析、资源管理(sched_getcpu)
  5. 容器技术:资源限制、进程隔离(prlimit64)

7.6 最佳实践

调度策略设置

c 复制代码
// 安全的调度策略设置
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 亲和性管理

c 复制代码
// 智能 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);
}

资源限制控制

c 复制代码
// 安全的资源限制设置
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 学习建议

掌握路径
1. 入门阶段 :理解基本调度概念和 sched_yield 使用
2. 进阶阶段 :掌握调度策略和 CPU 亲和性
3. 高级阶段 :精通资源限制和性能优化
4. 专家阶段:实现复杂的调度控制系统

实践要点

  • 从简单示例开始逐步复杂化
  • 重点关注权限管理和错误处理
  • 实际项目中验证调度效果
  • 持续关注实时系统发展

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

相关推荐
树℡独1 小时前
ns-3仿真之应用层(五)
服务器·网络·tcp/ip·ns3
嵩山小老虎2 小时前
Windows 10/11 安装 WSL2 并配置 VSCode 开发环境(C 语言 / Linux API 适用)
linux·windows·vscode
Fleshy数模2 小时前
CentOS7 安装配置 MySQL5.7 完整教程(本地虚拟机学习版)
linux·mysql·centos
a41324472 小时前
ubuntu 25 安装vllm
linux·服务器·ubuntu·vllm
Configure-Handler2 小时前
buildroot System configuration
java·服务器·数据库
津津有味道2 小时前
易语言TCP服务端接收刷卡数据并向客户端读卡器发送指令
服务器·网络协议·tcp·易语言
Fᴏʀ ʏ꯭ᴏ꯭ᴜ꯭.3 小时前
Keepalived VIP迁移邮件告警配置指南
运维·服务器·笔记
Genie cloud3 小时前
1Panel SSL证书申请完整教程
服务器·网络协议·云计算·ssl
一只自律的鸡4 小时前
【Linux驱动】bug处理 ens33找不到IP
linux·运维·bug
17(无规则自律)4 小时前
【CSAPP 读书笔记】第二章:信息的表示和处理
linux·嵌入式硬件·考研·高考