Linux进程管理子系统

《进程要素》

<进程与程序的区别>

程序:

存放在硬盘上一些列代码和数据的可执行映像,是一个静止的实体

进程:

是一个执行中的程序,是动态的实体

 

<进程4要素>

1)有一段程序供其执行,这段程序不一定是某个进程所专有,可以与其他进程所共用。

2)有进程所专用的内核空间堆栈

3)在内核中有task_struct()数据结构,即通常所说的进程控制模块(PCB)。有了这个数据结构,进程才能称为一个基本的单位接收内核的调度。

4)有独立的用户空间

 

有独立的用户空间:改程序就是一个进程

有共享的用户空间:用户线程

没有共享的用户空间:内核线程

 

 

<linux进程状态>

经典的进程状态

就绪:当进程被创建时一定处于就绪态

阻塞:当获取信息量不满足时,就会处于阻塞态

执行:当所有条件满足时就处于执行

 

linux进程状态:

 

TASK_RUNNING:

进程正在被CPU执行,或者已经准备就绪。随时可以执行,当一个进程被创建时,就处于该状态。

 

TASK_INTERRUPTIBLE:

处于等待中的进程,等待条件为真时被唤醒,也可以被信号或中断唤醒

 

TASK_UNINTERRUPTIBLE:

处于等待中的进程,待资源有效时被唤醒,但是不能由其他进程通过信号,或中断唤醒。

 

TASK_KILLABLE:

LINUX 2.6.25 中引入的进程睡眠状态,原理类似于TASK_UNINTERRUPTIBLE,但是可以被致命信号(SIGKILL)唤醒。

 

TASK_TRACED:

正处于被调试状态的进程

 

TASK_DEAD:

进程退出时(调用 do_exit()),所处的状态

 

 

<进程描述结构>

在linux内核代码中,进程和线程都使用结构体数组来表示,task_struct(sched.h),其中含有大量进程和线程的信息,其中比较重要的有:

pid_t pid;进程号

long state;进程状态

int prio;进程优先级

《linux进程调度》

从多个就绪状态的进程,选出一个进程来占有CPU来执行,称为进程调度

<调度策略>

SCHED_NORMAL(SCHED_OTHER):普通分时进程

SCHED_FIFO:先入先出的实时进程

SCHED_RR:时间片轮转的实时进程

SCHED_BATCH:批处理进程

SCHED_IDLE:只在系统空闲时才被调度的进程

 

注意:实时进程优先级最高,若果都是实时进程,则使用FIFO

 

<调度时机>

即shedule()函数什么时候被调用。

主动式:

在内核中直接调用函数schedule(),当进程需要等待资源而暂时停止运行时,会把自己的状体挂起(睡眠),并主动请求调度,并让出CPU.

例:

current -> state = TASK_INTERRUPTTBLE

Schedule()

 

用户态抢占:

发生时间:

1)从系统调用返回用户空间

比如,A进程中使用函数read(),则系统需要从用户态转换到内核态执行read()函数,在执行完read()后,返回用户空间时,这是来了一个B进程,且优先级比A进程高,这是就会把A进程踢开,占用CPU.

2)从用户中断处理程序返回用户空间

原理同上

 

详情:

内核将返回用户空间时,如果need_resched ,标志被设置,导致schedule()被调用,即发生抢占。

3)当一个进程的时间片被用完时,会设置need_resched

4)当一个优先级更高是进程进入可执行状态时,会设置need_resched

 

内核态抢占:


用户态枪战的缺陷:
进程或线程一旦进入内核态,就可以一直执行,知道他主动放弃,或时间片耗尽为止,这会导致紧急的进程线程长时间得不到运行,降低了整个系统的实时性。

 

改进方式:

允许系统在内核态也支持抢占,更高优先级的进程或线程可以抢占正在运行的低优先级的进程或线程。

 

1)中断处理程序完成,返回内核空间之前

2)当内核代码再一次具有可抢占性的时候如解锁或使能软中断

注意:不能抢占的情况

1)内核正在运行中断程序

2)内核正在进行上下文的Bottom half(中断的底半部)处理,硬件中断返回前会执行软中断,此时任处于中断上下文

3)进程正持有spinlock自旋锁,writelock/readlock读写功能锁。当持有这些锁时,不应该被抢占,否则抢占会导致其他进程长时间得不到锁,让进程成处于死锁状态。

4)内核正在执行调度程序scheduler,抢占的原因就是为了进行新的调度,没有理由将调度程序抢占再执行调度程序。

 

注意:

为了保证内核在以上几种状态下不被抢占,抢占式内核使用了一个变量preempt_count,称为内核抢占数。这一个变量被设置在进程的thread_info结构中,每当内核要进入以上几种状态时,变量preemt_count 就会加1,指示内核不允许抢占,每当内核从以上几种状态退出时,变量preempt_count 就会减1,同时进行可抢占的判断和调度。

 

<调度步骤>

清理当前正在运行的进程

选择下一个将要运行的进程(根据调度策略)

设置新进程 的运行环境

进程上下文切换

 

 

 

<wiz_tmp_tag id="wiz-table-range-border" contenteditable="false" style="display: none;">

posted @ 2018-03-17 15:01  流浪的Coder  阅读(515)  评论(0编辑  收藏  举报