linux进程管理

进程与线程

pcb

进程通过进程描述符(pcb)描述。在linux中pcb的结构体是 task_stack (在include/linux/sched.h) 包含了进程的状态信息、地址空间等进程的全部信息。通过pcb就可以恢复进程的状态。所以这里可以稍微说一下,进程切换其实就是将current_thread_info切换到对应的pcb,然后按照pcb中的信息恢复从而切换进程。

在这里插入图片描述

pcb一般被存储在内核空间的堆中,每个进程的task_stack由内核负责维护和管理。

进程创建与状态

进程通过 fork(内部调用clone) 从父进程创建出子进程。进程中有明显的继承关系。

fork 的过程:

  1. 子进程完全复制父进程的pcb
  2. 子进程设置成 uninterruptible状态
  3. 修改部分子进程的pcb的参数:某些flags、PID
  4. 根据clone 传入的参数拷贝/共享 文件、文件系统、信号、地址空间等
  5. 返回子进程指针

可以看到,子进程是"拷贝"了父进程的pcb,但其实此时只是将该pcb所占用的资源"只读"共享了。只有当涉及到需要写入的时候才真正的将数据拷贝,让各个进程有自己的拷贝。这是利用了 写时拷贝 的优化方式。

终结过程 exit

  1. 设置状态
  2. 删除定时器、输出记账信息
  3. 释放占用的mm
  4. 减少使用的文件的引用计数,如果为0直接释放
  5. 通知父进程
  6. 变成僵尸态,do_exit切换到别的进程再也不返回

下面是进程的状态
在这里插入图片描述

子进程终结的时候会通知父进程,父进程通过 wait 来回收子进程的资源。

  • 如果父进程没有回收->子进程为僵尸进程,无法被回收
  • 如果父进程先一步终结,子进程会被 init进程收养

线程

线程和进程在linux中其实没有严格区分,甚至可以看到线程的创建方式也是调用 clone

clone(CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, 0)

线程对于进程来说就是:和父进程共用虚拟内存,文件系统信息,打开的文件,信号的子进程

内核线程是由 kthread 进程中创建出来

进程调度

进程调度的方式:实时调度和非实时调度

进程切换的过程:
使用 schedule

  1. 将虚拟内存映射切换(MMU的页表地址切换)
  2. 从pcb中恢复新进程的状态

进程切换耗时(linux已经是轻量级了)的原因:pcb的切换消耗,需要更新MMU,可能会造成TLB flash等耗时操作。

CFS原因

一般进程有 IO密集型(例如:按键等需要读取IO)和处理器密集型(例如:视频编解码完全由CPU处理)两种。 但是这两种的需求和特点又十分不同:

  • IO密集型:处理时间短,但是需要快速响应,不然会感觉卡顿
  • 处理器密集型:处理时间长,不需要快速响应

linux就做了优化,依据nice(越小权重越高,可以获得更多的时间片)来为每个进程分配时间片,当时间片运行完自动切换到下一进程。这样就可以优先切换IO密集型的进程,这样可以做到快速响应,但是如何去判断什么时候优先切换,又如何判断是否是IO密集型就是问题了,并且nice分配时间片也会有很多问题(1.绝对值会造成0 1 与 18 19分配的时间差很多 2.不同的nice映射时间片不同并且时间片的时间还会随着定时器节拍改变)

所以linux对于非实时的普通进程使用CFS(完全公平调度)。

普通进程(SCHED_NORMAL)

CFS的含义:运行每一个进程都运行一段时间,循环轮转,然后选择调度运行时间最少的程序运行

对于普通进程,使用CFS来做调度策略。CFS不适用nice来分配时间片,而是使用vruntime来记录进程实际运行的时间,vruntime越小那么优先级越高,越优先调度。

CFS用红黑树来管理所有要执行的进程,这样每次只需要调度最左下角的进程(为了加速会缓存)。当进程暂停会从红黑树移除,放置到等待队列,当进程就绪后又会从等待队列删除添加回红黑树的运行队列中。

在等待队列中,会用while循环一直等待就绪的条件达成,当被唤醒后会再次的确认条件是否为真(查看是不是伪唤醒),如果确认条件满足了,才会退出循环。

实时进程(SCHED_FIFO | SCHED_RR)

这两个都和优先级强相关,不允许低优先级的抢占。如果只有低优先级,那么这两种都会一直执行不会切换。

SCHED_FIFO 就像名字所描述的,只要不自己主动放弃,或者自己收到阻塞,或者被优先级更高的打断,就可以一直执行下去

SCHED_RR = SCHED_FIFO+时间片。大部分和FIFO一样,但是对于同优先级的进程,还是会有时间片来管理切换进程。

实时进程类型低优先级同优先级高优先级
SCHED_FIFO不允许打断不允许打断打断
SCHED_RR不允许打断时间片切换打断

抢占

linux是支持用户抢占和内核抢占的。但是抢占必须在安全的时候,在调度的时候会有标志位来记录。

当从一个进程被抢占后,标志位 need_resched会置1,这样返回后,会认为要返回到原来的进程执行。

用户抢占

发生时机:

  1. 从内核返回到用户进程
  2. 从中断返回到用户进程

当返回的时候如果 need_resched为1,就会触发调度。并且从内核返回到用户认为是安全的,所以到用户的时候就可以直接再被调度抢占

内核抢占

对于内核线程来说,需要一个标志位preempt_count来标志用来计数(锁),如果计数不是0,那么切换的时候就是不安全的就不运行抢占,当计数是0的时候才运行抢占。

所以当 need_resched 为1,并且 preempt_count 为0,那么就认为有一个更需要调度的进程,就会触发schedule调度

调度时机:

  1. 中断返回内核前
  2. 内核线程被阻塞
  3. 再一次可以被抢占
  4. 手动触发 schedule (需要自己保证安全)
  • 12
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值