基于Linux进程模型分析
Posted jmu1079
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于Linux进程模型分析相关的知识,希望对你有一定的参考价值。
-
操作系统是怎么组织进程的
- 什么是进程
进程是处于执行期的程序以及它所包含的所有资源的总称,包括虚拟处理器,虚拟空间,寄存器,堆栈,全局数据段等。
在Linux中,每个进程在创建时都会被分配一个数据结构,称为进程控制块。进程控制块中包含了很多重要的信息,供系统调度和进程本身执行使用。而进程的用户空间主要存储代码和数据。
- 进程的创建
进程是通过调用::fork(),::vfork()和::clone()系统调用创建新进程,而且都是通过调用do_fork来实现进程的创建。
三者的区别如下:
- ::fork():父进程的所有数据结构都会复制一份给子进程。
- ::vfork():只复制task_struct和内核堆栈,所以生成的只是父进程的一个线程。
- ::clone():::clone()可以让你有选择性的继承父进程的资源,既可以选择像::vfork()一样和父进程共享一个虚拟空间,从而使创造的是线程,你也可以不和父进程共享,你甚 至可以选择创造出来的进程和父进程不再是父子关系,而是兄弟关系。
- 进程的退出
进程通过调用exit()退出执行,这个函数会终结进程并释放所有的资源。父进程可以通过wait4()查询子进程是否终结。进程退出执行后处于僵死状态,直到它的父进程调用wait()或者waitpid()为止。父进程退出时,内核会指定线程组的其他进程或者init进程作为其子进程的新父进程。
-
进程状态如何转换(给出进程状态转换图)
- 三种基本状态 :
运行态:进程占用CPU,并在CPU上运行;
就绪态:进程已经具备运行条件,但是CPU还没有分配过来;
阻塞态:进程因等待某件事发生而暂时不能运行;
状态转换图:
进程之间的转换过程:
运行---》就绪:这是有调度引起的,主要是进程占用CPU的时间过长
就绪---》运行:运行的进程的时间片用完,调度就转到就绪队列中选择合适的进程分配CPU
运行---》阻塞:发生了I/O请求或等待某件事的发生
阻塞---》就绪:进程所等待的事件发生,就进入就绪队列
阻塞--》运行:即使给阻塞进程分配CPU,也无法执行,操作系统載进行调度时不会載阻塞队列进行挑选,其调度的选择对象为就绪队列:
就绪--》阻塞:因为就绪态根本就没有执行
-
进程是如何调度的
- 进程的优先级
进程提供了两种优先级,一种是普通的进程优先级,第二个是实时优先级,前者使用SCHEED_NORMAL调度策略,后者可选SCHED_FIFO或SCHED_rr调度。任何时候,实时进程的优先级都高于普通进程,实时进程只会被更高级的实时进程抢占,同时实时进程之间是按照FIFO(一次机会做完)或者RR(多次轮转)规则调度的。
2. 主调度器schedule
schedule就是主调度器的工作函数, 在内核中的许多地方, 如果要将CPU分配给与当前活动进程不同的另一个进程, 都会直接调用主调度器函数schedule或者其子函数__schedule.
asmlinkage void __sched schedule(void) { struct task_struct *tsk = current; sched_submit_work(tsk); __schedule(); }
3.进程上下文的切换
context_switch其实是一个分配器, 他会调用所需的特定体系结构的方法
-
调用switch_mm(), 把虚拟内存从一个进程映射切换到新进程中
switch_mm更换通过task_struct->mm描述的内存管理上下文, 该工作的细节取决于处理器, 主要包括加载页表, 刷出地址转换后备缓冲器(部分或者全部), 向内存管理单元(MMU)提供新的信息
-
调用switch_to(),从上一个进程的处理器状态切换到新进程的处理器状态。这包括保存、恢复栈信息和寄存器信息
static void __sched __schedule(void) { struct task_struct *prev, *next; unsigned long *switch_count; struct rq *rq; int cpu; cpu = smp_processor_id(); rq = cpu_rq(cpu); rcu_note_context_switch(cpu); prev = rq->curr; //当前队列的当前进程 schedule_debug(prev); ... if (unlikely(!rq->nr_running))//当前rq无进程运行时,从其他cpu上取一个task执行 idle_balance(cpu, rq); //选择下个可调度进程 next = pick_next_task(rq); ... //上下文切换 context_switch(rq, prev, next); ... }
4.Linux的现代调度算法:CFS(完全公平调度)
CFS是完全公平调度算法,将所有的进程都统一对待。其中的schedule() 函数它会先抢占当前运行任务,当它开始确定下一个要调度的任务时,它会调用 pick_next_task 函数,通过调度器类调用 CFS 调度器,返回相关 的sched_entity。
static inline struct task_struct * pick_next_task(struct rq *rq) { const struct sched_class *class; struct task_struct *p; /*使用的数据结构*/ if (likely(rq->nr_running == rq->cfs.nr_running)) { //如果nr_running==cfs.nr_running,则说明当前rq队列中是没有rt任务的, //rt任务不在cfs队列中,它的优先级的设置和cfs不一样。 p = fair_sched_class.pick_next_task(rq); //在cfs队列中挑选即将被切换进去的进程 if (likely(p)) return p; } for_each_class(class) { p = class->pick_next_task(rq); if (p) return p; } }
-
对Linux操作系统的看法
Linux系统同时可以支持多个用户,每个用户对自己的文件设备有特殊的权利,能够保证各用户之间互不干扰。并且具有比window是更好的稳定性以及高效性。且Linux的操作与windows的操作相比更加简洁,在命令行和脚本上面的操作,只需要简单的几行命令就能完成鼠标需要点击很多次的操作功能。
-
参考资料
https://blog.csdn.net/jnu_simba/article/details/11724277
https://www.cnblogs.com/sky-heaven/p/8118110.html
以上是关于基于Linux进程模型分析的主要内容,如果未能解决你的问题,请参考以下文章