linux系统中调度策略(SCHED_BATCH、SCHED_DEADLINE、SCHED_IDLE、SCHED_FIFO、SCHED_RR、SCHED_OTHER)的介绍

在 Linux 系统中,除了常见的 SCHED_FIFOSCHED_RRSCHED_OTHER 调度策略外,还有 SCHED_BATCHSCHED_DEADLINESCHED_IDLE 等调度策略,它们各自适用于不同的场景。以下是对这些调度策略的介绍以及如何更改它们的方法

介绍


1. SCHED_BATCH

  • 特点SCHED_BATCH 是一种用于批处理任务的调度策略。它适用于那些对实时性要求不高但需要长时间运行的任务,例如后台计算任务。与 SCHED_OTHER 不同,SCHED_BATCH 会减少进程的调度频率,尽量让进程一次性运行更长时间,从而提高效率。
  • 适用场景:适合批处理任务,如科学计算、数据处理等。

2. SCHED_DEADLINE

  • 特点SCHED_DEADLINE一种实时调度策略,适用于对时间敏感的任务。它通过三个参数(运行时间、周期、截止时间)来管理任务的执行。例如,一个任务可能需要在每 100ms 的周期内运行 10ms,并且必须在 90ms 内完成。
  • 适用场景:适用于需要严格时间约束的实时任务,如工业自动化、音频处理等。

3. SCHED_IDLE

  • 特点SCHED_IDLE 是一种低优先级的调度策略,适用于那些只有在系统空闲时才运行的任务。它确保这些任务不会干扰其他更高优先级的任务。
  • 适用场景:适合低优先级的后台任务,如磁盘清理工具。

4. SCHED_FIFO

  • 特点SCHED_FIFO一种实时调度策略,采用先进先出的方式。一旦进程获得 CPU,它会一直运行,直到主动放弃 CPU 或被更高优先级的进程抢占
  • 适用场景:适用于对实时性要求极高的任务,如音视频处理

5. SCHED_RR

  • 特点SCHED_RR一种带有时间片的实时调度策略。它与 SCHED_FIFO 类似,但在时间片耗尽后会释放 CPU
  • 适用场景:适用于需要多个实时任务公平共享 CPU 的场景

6. SCHED_OTHER

  • 特点SCHED_OTHERLinux 系统中默认的调度策略,基于完全公平调度器(CFS)。它通过动态优先级和时间片来平衡系统中所有进程的 CPU 时间
  • 适用场景:适用于大多数普通用户程序和后台服务。

通过命令配置更改进程调度策略的方法

1. 使用 chrt 命令

chrt 是一个常用的命令行工具,用于设置或查看进程的调度策略和优先级。
在这里插入图片描述

  • 设置调度策略

    • 设置为 SCHED_FIFO

      chrt -f -p <优先级> <进程ID>
      

      例如,将进程ID为1234的调度策略设置为 SCHED_FIFO,优先级为99:

      chrt -f -p 99 1234
      
    • 设置为 SCHED_RR

      chrt -r -p <优先级> <进程ID>
      

      例如,将进程ID为1234的调度策略设置为 SCHED_RR,优先级为50:

      chrt -r -p 50 1234
      
    • 设置为 SCHED_OTHER(默认调度策略):

      chrt -o -p <进程ID>
      
  • 启动时指定调度策略: 如果需要在启动进程时指定调度策略,可以直接在 chrt 命令中指定:

    chrt -f 99 /path/to/your/application
    

2. 使用 systemd 配置文件

对于通过 systemd 管理的服务,可以在服务的配置文件中设置调度策略。

  • 在服务的 [Service] 部分添加以下配置:

    [Service]
    ExecStart=/path/to/your/service
    CPUSchedulingPolicy=fifo  # 或 rr/other
    CPUSchedulingPriority=99  # 对于实时策略,指定优先级
    
  • 示例(SCHED_FIFO):

    [Unit]
    Description=My Service
    
    [Service]
    ExecStart=/path/to/my/service
    CPUSchedulingPolicy=fifo
    CPUSchedulingPriority=99
    
    [Install]
    WantedBy=default.target
    
  • 修改配置后,需要重新加载 systemd 配置并重启服务:

    systemctl daemon-reload
    systemctl restart your-service-name
    

3. 内核参数调整

虽然内核参数主要用于调整调度器的行为,而不是直接更改调度策略,但某些参数可能会影响调度策略的效果。

  • 查看当前调度策略: 使用 ps 命令查看进程的调度策略:

    ps -eo pid,comm,policy
    
  • 调整实时进程的运行时间

    • sched_rt_period_us:实时进程的时间周期(默认1秒)。

    • sched_rt_runtime_us:实时进程在每个周期内的最大运行时间(默认0.95秒)。

    • 调整方法:

      echo 1000000 > /proc/sys/kernel/sched_rt_period_us
      echo 950000 > /proc/sys/kernel/sched_rt_runtime_us
      
  • 调整 SCHED_RR 的时间片

    • sched_rr_timeslice_ms:设置 SCHED_RR 的时间片大小(默认100ms)。

    • 调整方法:

      echo 100 > /proc/sys/kernel/sched_rr_timeslice_ms
      

注意事项

  1. 更改调度策略通常需要 root 权限。
  2. 实时调度策略(SCHED_FIFOSCHED_RR)的优先级范围是1(最低)到99(最高),默认调度策略(SCHED_OTHER)不支持优先级设置。
  3. 在生产环境中,建议谨慎使用实时调度策略,因为它们可能对系统资源分配产生较大影响。

通过编程的方式更改进程调度策略

在 Linux 系统中,可以通过 sched_setattr 系统调用设置进程的调度策略和相关参数。以下是一个使用 sched_setattr 的示例代码,展示如何设置不同的调度策略(如 SCHED_FIFOSCHED_RRSCHED_DEADLINE 等)。

示例代码

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>  // 包含 uint32_t 和 uint64_t 的定义
#include <linux/sched.h>
#include <unistd.h>
#include <errno.h>
//sched_setattr 和 struct sched_attr 的定义在某些情况下可能未被 glibc 包含,
//因此需要手动定义这些内容

// 手动定义 sched_attr 结构体
struct sched_attr {
    uint32_t size;
    uint32_t sched_policy;
    uint64_t sched_flags;
    int32_t sched_nice;
    uint32_t sched_priority;
    uint64_t sched_runtime;
    uint64_t sched_deadline;
    uint64_t sched_period;
};
// 手动定义系统调用号(x86_64 架构)
#define __NR_sched_setattr 314
#define __NR_sched_getattr 315  // x86_64 架构下的系统调用号

// 手动定义 sched_setattr 系统调用
int sched_setattr(pid_t pid, const struct sched_attr *attr, unsigned int flags) {
    return syscall(__NR_sched_setattr, pid, attr, flags);
}

int sched_getattr(pid_t pid, struct sched_attr *attr, unsigned int size, unsigned int flags) {
    return syscall(__NR_sched_getattr, pid, attr, size, flags);
}
int main() {
    struct sched_attr attr = {
        .size = sizeof(attr),
        .sched_policy = SCHED_FIFO,  // 设置为 SCHED_FIFO
        .sched_priority = 50,        // 设置优先级
        .sched_runtime = 0,          // 仅对 SCHED_DEADLINE 有效
        .sched_period = 0,           // 仅对 SCHED_DEADLINE 有效
        .sched_deadline = 0          // 仅对 SCHED_DEADLINE 有效
    };

    // 调用 sched_setattr 设置调度策略
    if (sched_setattr(0, &attr, 0) == -1) {
        perror("sched_setattr");
        return EXIT_FAILURE;
    }

    printf("调度策略设置成功,当前策略为 SCHED_FIFO,优先级为 %d\n", attr.sched_priority);
	
    // 等待一段时间,观察调度效果
    sleep(10);
	//获取一下设置的策略
	 // 获取当前进程的调度策略
    if (sched_getattr(0, &attr, sizeof(attr), 0) == -1) {
        perror("sched_getattr");
        return -1;
    }

    printf("当前调度策略: ");
    switch (attr.sched_policy) {
        case SCHED_FIFO:
            printf("SCHED_FIFO\n");
            break;
        case SCHED_RR:
            printf("SCHED_RR\n");
            break;
        case SCHED_IDLE:
            printf("SCHED_IDLE\n");
            break;
        case SCHED_DEADLINE:
            printf("SCHED_DEADLINE\n");
            break;
        default:
            printf("未知调度策略\n");
    }

    printf("优先级: %d\n", attr.sched_priority);
    return EXIT_SUCCESS;
}

示例代码说明

由于我的编译环境有点老glibc 并未直接支持这些较新的系统调用,代码中使用了 syscall 函数来直接调用内核提供的系统调用,编译会报如下错误:
在这里插入图片描述

代码逻辑说明
  1. 设置调度策略
    • 初始化 sched_attr 结构体,设置调度策略为 SCHED_FIFO,优先级为 50
    • 调用 sched_setattr 设置当前进程的调度策略。
    • 如果设置失败,打印错误信息并退出。
  2. 确认调度策略
    • 调用 sched_getattr 获取当前进程的调度策略。
    • 根据 sched_policy 的值,打印当前的调度策略和优先级。
  3. 观察调度效果
    • 在设置调度策略后,程序调用 sleep(10),等待 10 秒,以便观察调度策略的实际效果。

示例:设置 SCHED_RR 调度策略

将调度策略改为 SCHED_RR,并设置优先级为 30:

attr.sched_policy = SCHED_RR;
attr.sched_priority = 30;

示例:设置 SCHED_DEADLINE 调度策略

设置 SCHED_DEADLINE 需要额外的参数:

attr.sched_policy = SCHED_DEADLINE;
attr.sched_runtime = 10000000; // 10ms
attr.sched_period = 100000000; // 100ms
attr.sched_deadline = 100000000; // 100ms

示例:设置 SCHED_OTHER 调度策略

对于非实时调度策略(如 SCHED_OTHER),不需要设置优先级:

attr.sched_policy = SCHED_OTHER;
attr.sched_priority = 0; // 优先级对 SCHED_OTHER 无效

编译和运行

  1. 将代码保存为 set_sched.c

  2. 使用以下命令编译:

    gcc set_sched.c -o set_sched -lrt
    
  3. root 用户运行(因为设置实时调度策略通常需要管理员权限):

    sudo ./set_sched
    

注意事项

  1. 权限问题:设置实时调度策略(SCHED_FIFOSCHED_RRSCHED_DEADLINE)通常需要管理员权限。
  2. 实时优先级范围:实时调度策略的优先级范围是 1(最低)到 99(最高)。
  3. SCHED_DEADLINE 支持:需要 Linux 内核支持 SCHED_DEADLINE(通常需要较新的内核版本)。

通过以上代码和说明,你可以根据需要动态设置进程的调度策略。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值