<Linux>(极简关键、省时省力)《Linux操作系统原理分析之Linux 进程管理 3》(7)

《Linux操作系统原理分析之Linux 进程管理 3》(7)

  • [4 Linux 进程管理](#4 Linux 进程管理)
    • [4.3 Linux 的进程调度](#4.3 Linux 的进程调度)
    • [4.3.1 Linux 进程调度策略](#4.3.1 Linux 进程调度策略)
      • [4.3.2 Linux 进程调度依据](#4.3.2 Linux 进程调度依据)
      • [4.3.3Linux 进程调度的加权处理](#4.3.3Linux 进程调度的加权处理)
      • [4.3.4 Linux 进程调度方法](#4.3.4 Linux 进程调度方法)
      • [4.3.5 Linux 进程调度时机](#4.3.5 Linux 进程调度时机)

4 Linux 进程管理

4.3 Linux 的进程调度

4.3.1 Linux 进程调度策略

Linux 在进程调度中采用的是可抢占的调度方式。

Linux 中的进程分为普通进程和实时进程。实时进程的优先级高于普通进程。对实时进程和普通进程采用不同的调度策略。

Linux 为每个进程都规定了一种调度策略,并记录在其任务结构体 policy 成员项中。Linux 调度策略有3 种,它们以符合常量的形式定义

java 复制代码
在/include/linux/sched.h 中,其定义及意义如下所示:
#define SCHED_OTHER 0 普通进程的时间片轮转算法(根据优先权选择下一个进程)
#define SCHED_FIFO 1 实时进程的先进先出算法(适用于响应时间要求比较严格的短小进程)
#define SCHED_RR 2 实时进程的时间片轮转算法(适用于响应时间要求比较严格的较大进程)

因此在 linux 的可运行队列中,从调度策略来分 SCHED_FIFO 的实时进程具有最高优先级,其次是SCHED_RR 的实时进程,而 SCHED_OTHER 的普通进程优先级最低。

4.3.2 Linux 进程调度依据

Linux 的进程调度采用了优先级和权值的方法。Linux 用以下四个数据作为调度依据,它们记录在进程的任务结构体中:

👉Policy 是进程的调度策略

👉Priority 是普通进程的优先级。它是0\~70之间的数,数值越大优先级越高。Priority 除表示进程的优先级,还表示分配给进程使用 CPU 的时间片。

👉Rt_Priority 是实时进程的优先级。策略为 SCHED_FIFO 的实时进程的 rt_Priority 大于 SCHED_ RR 实时进程

👉Counter 中存放的是进程还需要使用 CPU 运行时间的计数值,它是动态变化的,它的初始值就是Priority。

4.3.3Linux 进程调度的加权处理

加权处理的方法:在进程调度过程中,每次选取下一个运行进程时,调度程序首先给可运行队列的每个进

程赋予一个权值(weight)。普通进程的权值就是它的 counter 值,而实时进程的权值是它的 rt_Priority 值

加 1000。Linux 使用内核函数 goodness()对进程进行加权处理,它的源程序在/kernel/sched.c 中,下面给出了

去掉其中多处理机(SMP)部分后简化的程序代码。

java 复制代码
Static inline goodness(struct task_struct *p, struct task_struct *prev, int this_cpu)
{
Int weight;
If(p->policy!=SCHED_OTHER) /*若当前进程是实时进程*/
Return 1000+p->rt_Priority; /*返回权值为 rt_Priority +1000*/
Weight=p->counter; /*若当前进程是普通进程*/
.........
.........
Return weight; /*返回权值为 counter */
}

4.3.4 Linux 进程调度方法

实时进程的优先级大于普通进程的优先级,故只有当可运行队列的所有实时进程都运行完成后,普通进程才能得到运行。

linux 普通进程的优先级由 Priority 和 counter 共同决定。在进程运行过程中 Priority 保持不变,体现了进程的静态优先级概念;而 counter 不断减少,表示了进程的动态优先级。采用动态优先级的方法,使得一个进程占用 CPU 的时间越长,counter 的值越小。这样使得每个进程都可以公平地分配到 CPU。

4.3.5 Linux 进程调度时机

Linux 进程调度是由 Schedule()完成的。该函数定义在/kernel/sched.c 中。执行该函数 的情况可以分

为两种:

在某些系统调用函数中直接调用 Schedule()。

在系统运行过程中,通过检查调度标志而执行该函数。进程调度标志是一个名为 need_resched 的 全局变量,当它的值为 1 时,表明需要执行调度函数。

1.进程状态发生变化时

Linux 进程状态不断发生变化,在下列状态转换是需要执行进程调度:

1)当前进程进入等待状态

例如,运行态的进程可以通过执行系统调用 sleep_on()主动放弃 CPU 而进入等待状态 。

java 复制代码
Sleep_on()的部分源代码如下:
Current->state=state; /* 把当前进程状态设置为等待状态*/
Save_flags(flags);
_add_wait_queue(p,&wait); /*把当前进程加入等待队列*/
Sti();
Schedule(); /*执行进程调度*/
Cli();

2)运行态下的进程运行结束后 运行态下的进程运行结束后

一般通过调用内核函数 do_exit()终止运行进程并转入僵死状态。该函数部分源码:

java 复制代码
......
Current->state = TASK_ZOMBIE; /*把当前进程设置为僵死状态*/
......
Schedule();/*执行调度程序*/
......

3)使用使用 wake_up_process()将处于等待状态的进程唤醒,然后将它置于可运行状态 然后将它置于可运行状态。该函数部分源码:

java 复制代码
Save_flags(flafs);
Cli();
p->state = TASK_RUNNING; /*把进程置为可运行态*/
if(!p--->next_run)
add_to_runqueue(p); /*加入到可运行队列*/
restore_flags(flags);
if(p->counter>current->counter+3)
need_resched =1; /*调度标志置位,执行进程调度*/

4)当一个进程的程序接受调试时 当一个进程的程序接受调试时,调式进程向被调试进程发送 SIGSTOP 信号,被调试进程处理该信号时调用内核函数 do_signal()。

部分源码:

java 复制代码
Current->state = TASK_STOPPED /*把当前进程置为暂停态*/
Notify_parent(current);
Schedule();/*执行进程调度*/

5)当被调试的进程接收到调试进程发送的 SIGCONT 信号时,执行 send_sig(),其中使用wake_up_process()解除被调试进程的暂停态而重新进入可运行态。

java 复制代码
If(sig==SOGKILL||sig==SIGCONT))
{
If(p->state==TASK_STOPPED) /*若进程为暂停态*/
wake_up_process(p);

2.当前进程时间片用完时

在进程时间片运行完时,需要将 CPU 重新分配给下一个被选中的进程,这个过程是在时钟中断中实现。在时钟中断处理程序中调用了内核函数 update_process_times(),它用于更新进程的各个时间信息,其中包括下面语句:

java 复制代码
p->counter -= ticks
if(p->counter<0)
{
P->counter=0;
Need_resched=1;
}

3.进程从系统调用返回用户态时

当进程从系统调用返回用户态时,需要执行内核的汇编例程 ret_from_sys_call,其中包括对need_resched 标志进行检测的指令。

java 复制代码
Cmpl $0,need_resched
Jne reschedule
当 need_resched=1 时,就转移到 reschedule。
Reschedule:
Call SYMBOL_NAME(schedule)

4.中断处理后,进程返回用户态时

同 3,当中断处理结束后,也需要执行内核的汇编例程 ret_from_sys_call

相关推荐
律宏阔2 小时前
WSL Docker 端口明明空闲,但就是绑不上端口
linux·windows
律宏阔2 小时前
WSL 突然断网,无法 ping 内网或外网
linux·windows
穷人小水滴2 小时前
用容器编译 VirtualBox 虚拟机软件 (ArchLinux, podman)
linux·容器·virtualbox
乱码三千2 小时前
如何优雅地直连无公网 IP 的远程 GPU 服务器
linux·人工智能·程序员
yunwei372 小时前
使用 eBPF 跟踪 Nginx 请求
linux·后端·性能优化
yunwei372 小时前
使用 eBPF 跟踪 MySQL 查询
linux·后端·性能优化
yunwei372 小时前
eBPF 示例教程:使用 XDP 捕获 TCP 信息
linux·后端·性能优化
judezh2 小时前
api 容器一直 unhealthy?我把一个 Agent 运行时的健康检查逐条拆了,查出四个问题
运维·docker
GeW2 小时前
制造业高端化,为什么必须重估Linux和数据库?
linux
百万蹄蹄向前冲2 小时前
双端同步!云服务器装最新Node.js v26.10全过程追踪
服务器·人工智能·node.js