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 调度系统的强大功能。

相关推荐
专注VB编程开发20年2 小时前
用ADO操作EXCEL文件创建表格,删除表格CREATE TABLE,DROP TABLE
服务器·windows·excel·ado·创建表格·删除表格·读写xlsx
水冗水孚2 小时前
😱😱😱CPU和内存飙到100%——我的火山引擎服务器被印度的ip恶意植入挖矿程序了!😡😡😡
服务器·ubuntu·centos
wanhengidc3 小时前
DDOS攻击和CC攻击对服务器的伤害有哪些?
运维·服务器·ddos
春时似衿里3 小时前
【Navicat 连接MySQL时出现错误1251:客户端不支持服务器请求的身份验证协议;请考虑升级MySQL客户端】
服务器·数据库·mysql
帅帅梓3 小时前
Linux lvm逻辑卷管理
linux·运维·数据库
上海云盾商务经理杨杨3 小时前
2025年服务器僵尸攻防战:从AI勒索到量子免疫,构建下一代“数字抗体”
运维·服务器·人工智能
科大饭桶3 小时前
Linux系统编程Day5 -- Vim工具的使用
linux·运维·服务器·c语言·c++
XR101yqm12213 小时前
川翔云电脑:引领开启算力无边界时代
服务器·网络·云计算
I'm a winner3 小时前
基于 Ubuntu 的 Linux 系统中 Vivado 2020.1 下载安装教程
linux·ubuntu·fpga开发