《2022年操作系统进程模型》由会员分享,可在线阅读,更多相关《2022年操作系统进程模型(5页珍藏版)》请在金锄头文库上搜索。
1、操作系统进程模型进程的相关概念进程是一个程序的一次执行,这是一个动态的过程,一个进程包括了程序计数器、寄存器和变量的当前值。在多道程序中有多个进程同时在运行,从概念上他们有各自的CPU ,实际上是一个CPU在各个进程之间快速地切换。每个进程靠自己独有的程序计数器来控制自己的程序执行流程, 实际的物理程序计数器只有一个,当某个进程获得物理CPU时它的逻辑程序计数器就被装入实际的程序计数器中。进程有其从创建到销毁的生命周期。进程存在的意义就是完成一定的任务,通常将进程分为前台进程和后台进程。前台进程负责与用户交互,如用户可以终端上输入命令启动程序;后台进程不与特定的用户关联,负责处理一些专用的事件
2、,比如监听网络端口的请求,后台进程又称为守护进程。进程完成它的工作后就自动退出,释放占用的系统资源。进程并不是在所有情况下都 “自愿” 退出的, 它可能是由另外的进程杀死的,也可能是因为执行期间发生了严重错误被系统强制终止的。有些进程是被操作系统生成的,有些进程是由其他进程创建的(即父进程创建子进程)。在 Minix 和 Linux 系统中第一个用户进程init进程是由操作系统创建的,此后的所有进程都是init进程的子进程或孙进程。进程之间形成一种树状的层次结构。虽然每个进程都是一个独立的实体,有它自己的程序计数器、堆栈、 打开的文件、 定时器和内部状态, 但进程之间还要进行交互、通信以及其他
3、同步操作。由于进程之间要相互依赖,同步执行, 这就决定了进程从创建开始是很难一口气执行到底的,进程调度也要求进程中执行期间必须有间歇。大体上我们把进程的状态分为三种:运行态、 就绪态和阻塞态。进程处于运行态是指它正在占用CPU 。从运行态转入就绪态仅仅是因为处理机的调度策略使把正在执行的进程换出CPU ,转而去执行其他进程,当调度策略又转回来时,处于就绪态的进程就可以立刻执行。从运行态转入阻塞态就由于进程缺少某种必须的资源,如程序要执行必须是等待用户参数的输入,当阻塞的进程获得这种资源后就转入就绪态,只要调度策略允许它随时可以执行。就像刚刚提到的那样,就绪队列中有多个进程时它们都可以马上运行,
4、那么到底运行哪个呢?这是由调度器来决定的。最简单最直观的调度算法是维持一个单一的就绪队列,谁先到达队列中谁先执行。在实际的系统中往往给进程分配一定的优先级,优先级高的进程虽然后到达就绪队列, 但由于它要执行的事情紧急调度器可以让它先执行。系统中优先级数目是有限制的, 我们只能把若干个进程统一规为一种优先级,在同一个优先级内部采用先到先运行的法则。为避免那些优先级别低的进程长时间等待甚至是“饿死”,操作系统还采用一定的策略来逐步降低执行频率高的进程的优先级。在操作系统中协作的进程间要对某块公共存储区进行读写,这个公共存储区可能在主存中(比如是一个内核数据结构),也可能是一个共享文件。由于进程何时
5、运行何时休眠,基于什么时候产生、 什么时候终止都是无法预知的,那么不了的进程对同一存储区的读写顺序也是无法预知的, 因此我们要有一种机制来实现进程间的同步。我们把不同进程共享的内存区称为临界区, 当一个进程进入临界区后,其他进程必须在外面等待,同时还要选择一种策略使在临界区外面等的进程不能无限期的等下去,即要公平地为进程分配进入临界区的机会和时间。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 1 页,共 5 页 - - - - - - - - - Minix 进程模型系统结 构Mi
6、nix系统整体采用四层结构,如下图所示: 图 1. Minix四层结构内核负责进程的调度,并负责进程在运行态、就绪态和阻塞态之间切换。内核还负责进程间所有的通信消息,消息需要核实目标的合法性,定位内存中发送和接收的缓存区,并把消息从发送缓存复制到接收缓存。内核的另一部分是支持对I/O 端口和中断的访问。内核以上的其他三层统称为用户层,内核对这三层同等对待。它们都不直接对I/O 进行操作,也不能访问分配给他们以外的内存。第 2 层设备驱动程序层可以请求系统任务任代表它们从 I/O 端口读数据或向I/O 端口写入数据。第 3 层上是服务器进程,即向用户进程提供有用的服务。有两个服务必不可少:进程管
7、理器和文件系统。进程管理器执行所有涉及启动或终止进程的Minix系统调用,如fork ,exec,wait 等,并负责执行与信号有关的系统调用,如 alarm ,kill。进程管理器还负责内存管理,如brk 系统调用。文件系统负责执行文件的系统调用,如read ,mount,chdir等。再生服务器启动或重启那些不与内核一起加载到内存中的设备驱动程序。如果驱动程序在操作中失败,再生服务器检测到这一失败,并杀死这个驱动程序(如果它还没有死),重启这个驱动程序的一个新副本,从而提高操作系统的容错能力。第 2 层和第 3 层内的设备驱动程序和服务器统称为系统进程,它是操作系统的一部分,不属于某一特定
8、用户,并且大部分在第一个用户登录前启动。第 4 层是所有的用户进程,如 shell程序、编辑器、编译器、用户程序等。许多用户进程是随着用户的登录、工作、 退出而创建和销毁的,而有些进程是从系统启动时创建并一直运行的。守护进程(daemon )是周期性地运行或一直等待某个事件的后台进程。进程的 创建当硬盘启动Minix系统时,硬盘的第一个磁道第一个扇区512 字节是一个主引导记录(MBR ,master boot record ) ,它包含了一段可执行程序的一个磁盘分区表。执行这段程序并读入分区表选择活动分区。活动分区的第一个扇区有一个引导程序,引导程序执行后启动boot 程序。 Boot 程序
9、找到引导镜像(Boot Image) ,并把引导镜像中的各个文件分装到内存的适当位置。 引导镜像中几个重要的文件是内核、进程管理器、 文件系统、 再生服务器、 Init进程等。Init进程作为第1 个用户进程也是作为引导镜像的一部分加载的最后一个进程,它在系统运行期间一直存在。一个Minix用户启动多个shell,在 shell里面执行自己的进程,名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 2 页,共 5 页 - - - - - - - - - 各个 shell都是 init的子
10、进程, 而用户进程则是init的孙进程, 所有的用户进程都是同一棵进程树的组成部分。Fork 系统调用是创建新进程的唯一途径,exec 允许一个进程执行一个指定的程序。进程间通信Minix提供三条原语来发送和接收消息:send ( dest , &message ) ; 用来向进程dest 发送一条消息,receive ( source , &message ) ; 用来接收一条来自进程source 的消息,sendrec ( src_dst , &message ) ; 用来发送一条消息并等待同一个进程的应答。对于 sendrec 进程把消息发送出去后把自己阻塞等待应答,应答消息将覆盖原先的
11、消息。有时候需要不阻塞的消息发送。notify(dest )调用不阻塞的, 即不管接收都是否正在等待消息,发送者都将继续执行。因为通知消息不阻塞,所以可以用它来避免死锁。进程调度Minix调度器拥有一个16 级的排除系统。最低级别的是IDLE 进程,用户进程启动时默认的优先级会比IDLE 进程的优先级高一些。在 Minix 四层结构中, 用户进程的优先级最低,服务器进程次低,驱动程序比前两者要高,而时钟和系统任务则处于最高的优先级别上。此外针对不同类别的进程它所分到的时间片(即进程在被抢占前所允许运行的最大时间间隔)也是不同的。用户进程拥有一个较小的时间片,驱动程序进程和服务器进程可以运行到阻
12、塞,但它们是可强占的。 当一个优先级高的进程超时运行时将把该进程放到一个较低优先级队列的队尾, 如果下一次这个进程又运行超时,那么它的优先级将再被降低一级。当然被降了级的进程其优先级也还是有机会得到提高的,这种情况发生在它用完了时间片但没有妨碍其他进程运行时。Linux 进程模型进程结构Linux中每个进程被创建时都会拥有一个进程标识符(PID) 。进程标识符不是进程在task 向量表中的索引,而是032767 之间的一个整数,在进程创建时动态生成。在Linux内核中有一个相当大的数据结构task_struct(在文件 /usr/src/linux-headers-2.6.32-25 / in
13、clude/linux/sched.h中)来描述进程,此结构中除了进程所必需的数据外,还包含了大量其他的数据来统计和维护与其他进程的关系。我们不去细究task_struct的每一项, 在Shell中输入 ps -aux来查看当前所有已打开进程的相关信息:USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 921 2.2 2.1 29092 22248 tty7 Rs+ 09:58 0:54 /usr/bin/X :0 - root 928 0.0 0.0 1792 560 tty4 Ss+ 09:58 0:00 /sbin/g
14、etty -8 ,USRE 项给出进程的属主,task_struct结构中有4 对用户和组标识符:(1)uid 和 gid 运行该进程的用户ID 和组 ID ,通常是进程创建者的uid 和 gid 。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 3 页,共 5 页 - - - - - - - - - (2)euid 和 egid 有效 uid 和 gid 。(3)fsuid和 fsgid 文件系统uid 和 gid 。(4)suid 和 sgid 备份 uid 和 gid 。这是
15、POSIX标准的要求。PID 是进程标识符, %CPU 代表该进程对CPU的占用率, %MEM 是内存占用率, VSZ指出进程的虚拟内存大小,RSS是驻留中页的数量,TTY是终端 ID。STAT是进程的状态。Linux 可以使用以下状态:D- 不可中断等待状态。进程在等待队列中,正在等待被唤醒。处于这种状态的进程只能显示被唤醒,不能被信号或中断自动唤醒。R- 正在运行可或在就绪队列中,处于这种状态的进程可以参与进程的调度。S- 可中断等待状态。处于等待队列中,正在等待某事件或资源。这种进程可以被信号或中断唤醒。T- 暂停状态, 可以再恢复。 导致进程暂停的原因可分为两类:收到了 SIGSTOP
16、 、SIGSTP 、SIGTTIN、 SIGTTOU等信号;受到其他进程(如Debug 进程)的追踪。系统调用ptrace可以停止被追踪的进程。Z- 僵尸进程。在Linux 进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果他的父进程没安装 SIGCHLD 信号处理函数调用 wait或 waitpid()等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么 in
17、it进程自动会接手这个子进程,为它收尸,它还是能被清除的。START 是进程开始运行的时间,TIME是进程运行持续的时间,COMMAND是进程命令对应的文件。当调用 ps lax还会看到进程有下面几个属性:PPID进程的父进程ID。NI- 进程的 NICE值,数值大,表示较少占用CPU时间。WCHAN进程等待的资源。进程调度Linux中进程调试都是非强占式的,系统采用相当简单的基于优先级的调试算法。进程只能在核心态等待,当进程执行系统调用时它会从用户态“陷入”核心态,这时内核代表这个进程执行。当进程在核心态等待某事件时,系统会将它挂起,而后让另一个进程运行。 Liunx 的调度函数是sched
18、ule ,定义在 kernel/sched.c中。 Schedule 函数完成以下工作:(1) 定义两个指针。prev 是正在运行的进程,next 是调度程序选择下一个将要运行的进程。这两个指针可能会相同。(2)处理调度任务队列。首先检查任务是否在队列中,如果有等待处理的任务则顺序处理其中的每一个任务,然后将队列清空。(3)检查任务是否在中断队列中,如果在,则不做本次调度,直接返回。(4)底半处理。就是中断处理的后半部分。(5)调度运行进程队列。与Minix不同的是Linux没有将可运行进程按其优先级分成多个队列,而是把系统中所有可运行进程(状态为TASK_RUNNING)都排在同一个队列中,
19、这实际上是一个双向链表,如下图所示:名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 4 页,共 5 页 - - - - - - - - - 图 2. 运行进程队列当调度策略是SCHED_RR 时,并且时间片已耗尽,则当前进程的时间片重新设置为它的优先级, 并将其移至队尾。 如果当前进程处于可中断等待状态,而且进程已经有了待处理的信号,则将其状态改为TASK_RUNNING,保留在进程队列中,参加此次调度。如果进程处于僵尸状态( TASK_ZOMBIE) 、不可中断等待状态(TASK_
20、UNINTERRUPTIBLE) 、暂停状态( TASK_ STOPED )则进程不参加此次调度,将其从运行队列中摘除。如果此次调度是因为当前进程超时而引起的,则当前进程的状态保持TASK_RUNNING,仍让它保留在运行队列中,参加此次调度。最后将当前进程的need_resched 标志清 0。(6)选择下一个要运行的进程。从 init_task.next开始,顺序搜索运行进程队列,对每一个进程计算其weight值,选择weight 值最大的运行。weight值的计算规则是:1. 如果当前进程声明要放弃CPU (进程调度策略中设置了SCHED_YIELD 位) ,则其 weigt=0 。2.
21、如果进程是实时进程,则weight=rt_priority+1000。 3. 如果进程的counter值为 0,则weight=0 。4. 如果进程的counter不为 0,则 weight=counter+priority;如果进程是当前进程,则其weight值再加 1,即当前进程优先。(7)切换。 保存当前进程结构(task_struct)中的上下文, 就是当前进程运行到调度程序结束时处理器的上下文。新加载进程的上下文也是它上次运行到调度地的快照,包括进程的程序计数器和各寄存器的内容。进程通信Linux 提供了多种进程间的通信(IPC)机制,信号是最基本的一种,管道是较常用的一种,此处Li
22、nux还支持 System V 的 IPC 机制,如信号灯、消息队列、共享内存等。信号是 Linux内核不可分割的一部分,其它 IPC 机制都是可选的。 信号的产生可以源自异常、中断、进程和内核。异常指进程运行中出现非法操作。中断如键盘操作、时钟中断。一个进程可以向另一个或一组进程发送信号,来通知事件、 控制作业。 内核通过信号通知进程中发生的事件,如进程使用资源超限。发发信号用send_sig_info函数,函数定义如下:int send_sig_info(int sig , struct siginfo *info, struct task_struct *t); sig 是要发送的信号,
23、info是信号的附加信息,t 是接收信号的进程。函数 do_signal为每一外当前未阻塞的信号检查sigaction结构,以确定如何处理它。当一个进程接受到某个信号后,它有一个缺省的动作,包括异常终止、退出、忽略、停止、继续。函数do_signal是所有信号处理的入口,其定义如下:int do_signal(struct pt_regs *regs,sigset_t *oldset); 管道是单向的、 先进先出的、 无结构的、 固定大小的字节流,它把一个进程的标准输出和另一个进程的标准输入连接在一起。写进程在管道尾端写入数据,读进程在管道首端读出数据。当管道满时写进程阻塞,管道为空时读进程阻塞。名师资料总结 - - -精品资料欢迎下载 - - - - - - - - - - - - - - - - - - 名师精心整理 - - - - - - - 第 5 页,共 5 页 - - - - - - - - -