进程
1.什么是进程?
程序:程序是指令和数据的集合
进程:进程就是程序的一次执行过程,是系统进行资源分配和调度的基本单位
2.如何操作进程?
设立了PCB (进程控制块),其内容如下。
标示符:描述本进程的唯一标示符,用来区别其他进程。
状态:任务状态,退出代码,退出信号等。
优先级:相对于其他进程的优先级。
程序计数器:程序中即将被执行的下一条指令的地址。
内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
上下文数据:进程执行时处理器的寄存器中的数据。
I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
记账信息:可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。 其他信息
CPU对进程的调度使用
CPU通过PCB中的内存指针来找到程序在内存中的地址,通过上下文数据来记录运行中程序的各种信息,通过程序计数器来找到这个程序即将执行的下一条指令的地址。
3.进程的状态
三种基本状态:就绪、运行、阻塞
五种状态:新建状态,就绪状态,运行状态,阻塞状态,退出状态。
4.子进程
当我们在一个已经创建的进程内通过fork创建一个新的进程时,这个新的进程就是原先进程的子进程。
在子进程创建的时候,它从父进程的PCB中复制了很多数据,如内存指针、上下文数据、程序计数器等,所以它的代码、数据以及运行的位置,都与父进程一模一样。
由于代码段是只读的,所以两者的代码都一样,不可修改,而两者虽然虚拟地址相同,但物理地址不同,所以两者的数据都各自独立。
一般来说,子进程先结束执行,然后父进程负责子进程的一些善后工作(回收资源)。
总结一下就是:父子进程代码共享,数据各自开辟空间。(利用写时拷贝技术)
我们创建子进程,希望它和父进程执行不一样的操作,该怎么实现呢?
最简单的方法就是通过fork的返回值来进行代码分流,父进程的返回值是子进程的pid,而子进程的返回值是0,通过对返回值的判断,即可完成代码的分流。
5.进程的概念
僵尸进程:
一个进程的子进程退出执行后,父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中,这种进程称之为僵死进程。
子进程的进程号就会一直被占用,但是系统所能使用的进程号有限,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。
解决方法有两种分别是退出父进程和进程等待。
孤儿进程:
父进程运行结束,但子进程还在运行(未运行结束)的子进程就称为孤儿进程。孤儿进程最终会被init进程(进程号为1)所收养,因此init进程此时变成孤儿进程的父进程,并由init进程对它们完成状态收集工作。(linux下,init是内核启动的第一个用户级进程,init有许多很重要的任务,比如像启动getty(用于用户登录)、实现运行级别、以及处理孤立进程。)
守护进程:
守护进程也就是通常说的Daemon进程(精灵进程),是Linux中的后台服务进程,是特殊的孤儿进程。生存期较长,通常独立于控制终端(不会因为控制终端被关闭而中断)并且周期性地执行某种任务或等待处理某些发生的事件。举例:nignx、mysql、cron都是守护进程。
6.进程控制
创建进程
fork:创建一个子进程,父子进程代码共享,数据独有。(共享是因为页表的权限,独有是不同的页表对应空间存数据)
vfork:创建一个子进程,并且阻塞父进程,直到子进程退出或者程序替换,父进程才继续运行
终止进程
return:只可以在 main 函数中用,推出后刷新缓冲区
exit(statu):库函数,退出刷新缓冲区
_exit(statu):系统调用,status 定义了进程的终止状态,父进程通过wait来获取该值,退出不刷新缓冲区
进程等待
wait:获取退出子进程的pid,并且释放子进程资源。( 阻塞:为了完成某个功能发起调用,如果不具备完成功能的条件,则调用不返回一直等待。非阻塞:为了完成某个功能发起调用,如果不具备完成功能的条件,则立即报错返回 )
waitpid:可以指定等待一个子进程的退出
程序替换
创建的子进程如果想要做与父进程不同的事,其最好的方法就是程序替换,替换一个进程正在调度的程序信息。
exec
l(list):表示参数采用列表
v(vector):参数用数组
p(path):有p自动搜索环境变量PATH
e(env):有e表示自己维护环境变量
7.进程的调度算法
针对批处理系统:批处理系统没有太多的用户操作,在该系统中,调度算法目标是保证吞吐量和周转时间(从提交到终止的时间)。
1.1先来先服务 first-come first-serverd(FCFS)
非抢占式的调度算法,按照请求的顺序进行调度。有利于长作业,但不利于短作业,因为短作业必须一直等待前面的长作业执行完毕才能执行,而长作业又需要执行很长时间,造成了短作业等待时间过长。
1.2短作业优先 shortest job first(SJF)
非抢占式的调度算法,按估计运行时间最短的顺序进行调度。如果一直有短作业到来,长作业可能处于一直等待短作业执行完毕的状态,导致饿死。
1.3最短剩余时间优先 shortest remaining time next(SRTN)
最短作业优先的抢占式版本,按剩余运行时间的顺序进行调度。当一个新的作业到达时,其整个运行时间与当前进程的剩余时间作比较,如果新的进程需要的时间更少,则挂起当前进程,运行新的进程。
交互式系统:交互式系统有大量的用户交互操作,在该系统中调度算法的目标是快速地进行响应。
2.1时间片轮转
将所有就绪进程按 FCFS 的原则排成一个队列,每次调度时,把 CPU 时间分配给队首进程,该进程可以执行一个时间片。当时间片用完时,由计时器发出时钟中断,调度程序便停止该进程的执行,并将它送往就绪队列的末尾,同时继续把 CPU 时间分配给队首的进程。时间片轮转算法的效率和时间片的大小有很大关系:
因为进程切换都要保存进程的信息并且载入新进程的信息,如果时间片太小,会导致进程切换得太频繁,在进程切换上就会花过多时间。而如果时间片过长,那么实时性就不能得到保证。
2.2优先级调度
为每个进程分配一个优先级,按优先级进行调度。为了防止低优先级的进程永远等不到调度,可以随着时间的推移增加等待进程的优先级。
2.3 多级反馈队列
一个进程需要执行 100 个时间片,如果采用时间片轮转调度算法,那么需要交换 100 次。多级队列是为这种需要连续执行多个时间片的进程考虑,它设置了多个队列,每个队列时间片大小都不同,例如 1,2,4,8,..。进程在第一个队列没执行完,就会被移到下一个队列。这种方式下,之前的进程只需要交换 7 次。每个队列优先权也不同,最上面的优先权最高。因此只有上一个队列没有进程在排队,才能调度当前队列上的进程。可以将这种调度算法看成是时间片轮转调度算法和优先级调度算法的结合。