linux教程第05课进程控制.ppt

上传人:小飞机 文档编号:6511287 上传时间:2023-11-08 格式:PPT 页数:41 大小:269.50KB
返回 下载 相关 举报
linux教程第05课进程控制.ppt_第1页
第1页 / 共41页
linux教程第05课进程控制.ppt_第2页
第2页 / 共41页
linux教程第05课进程控制.ppt_第3页
第3页 / 共41页
linux教程第05课进程控制.ppt_第4页
第4页 / 共41页
linux教程第05课进程控制.ppt_第5页
第5页 / 共41页
点击查看更多>>
资源描述

《linux教程第05课进程控制.ppt》由会员分享,可在线阅读,更多相关《linux教程第05课进程控制.ppt(41页珍藏版)》请在三一办公上搜索。

1、第5章 Linux内核简介,主要内容Linux核心的一般结构进程的概念、进程的调度和进程通信文件系统的构成和管理内存管理设备驱动及中断处理,5.1 概 述,Linux系统大致可分为三层:靠近硬件的底层是内核,即Linux操作系统常驻内存部分。中间层是内核之外的shell层,即操作系统的系统程序部分。最高层是应用层,即用户程序部分,从结构上看,Linux操作系统是采用单块结构的操作系统。一般说来,可以将操作系统划分为内核和系统程序两部分。,进程控制系统用于进程管理、进程同步、进程通信、进程调度和内存管理等。内存管理控制内存分配与回收。文件系统管理文件、分配文件空间、管理空闲空间、控制对文件的访问

2、并为用户检索数据。Linux系统支持三种类型的硬件设备:字符设备、块设备和网络设备。核心底层的硬件控制负责处理中断以及与机器通信。,启动一个Linux系统的过程是:一个不隶属于任何操作系统的加载程序将Linux部分内核调入内存,并将控制权交给内存中Linux内核的第一行代码。此后Linux要将自己的剩余部分全部加载到内存、初始化所有的设备、在内存中建立好所需的数据结构(有关进程、设备、内存等)。到此为止,Linux内核的工作告一段落,内核已经控制了所有硬件设备。至于操作和使用这些硬件设备,则属于系统部分。内核加载设备并启动init守护进程,init守护进程会根据配置文件加载文件系统、配置网络、

3、服务进程、终端等。一旦终端初始化完毕,我们会看到系统的欢迎界面了。,系统调用和库函数,系统调用是操作系统提供的、与用户程序之间的接口,也就是操作系统提供给程序员的接口 从感觉上系统调用类似于过程调用,都由程序代码构成,使用方式相同 两者有实质差别:过程调用只能在用户态下运行,不能进入核心态;而系统调用可以实现从用户态到核心态的转变。系统调用可大致分为五个类别:进程控制、文件管理、设备管理、信息维护和通信,库函数,它们本身并不属于操作系统的内核部分 库函数可以分为下面六大类:文件管理 状态信息 文件修改 程序设计语言的支持 程序装入和执行 通信,调用方式例如,creat系统调用可以创建一个新文件

4、,其函数原型说明如下:#include#include#include int open(const char*path,int oflags);不同的系统调用所需要的头文件(又称前导文件)是不同的。,5.2 进 程 管 理5.2.1 进程和线程的概念,1进程及其状态简单说来,进程就是程序的一次执行过程。进程至少要有三种基本状态。这三种基本状态是:运行态、就绪态和封锁态(或等待态)。进程的状态可依据一定的条件和原因而变化,进程控制块,进程的物理表示,2Linux进程状态,3进程的模式和类型在Linux系统中,进程的执行模式划分为用户模式和内核模式按照进程的功能和运行的程序来分,进程划分为两大类

5、:一类是系统进程,另一类是用户进程,4Linux线程Linux把线程定义为进程的“执行上下文”具有一段可执行的程序、专用的系统堆栈空间、私有的“线程控制块”(即thread_struct数据结构)缺少自己的存储空间,linux进程的概念,Linux操作系统包括三种不同类型的进程,每种进程都有自己的特点和属性:交互进程:由shell启动的进程。批处理进程:这种进程和终端没有联系,是一个进程序列。守护进程(dameon进程):在后台持续运行的进程。,进程管理命令,进程查看命令 ps ps 选项主要选项的含义如下:-e:显示所有进程;-h:不显示标题;-l:采用详细的格式来显示进程;-a:显示所有终

6、端上的进程,包括其他用户的进程;-r:只显示当前终端上正在运行的进程;-x:显示所有进程,不以终端来区分;-u:以用户为主的格式来显示进程;,删除进程命令killkill-s|-p-a.kill-s|-p-a.kill-l 信号 选项的含义如下:-s:指定需要送出的信号。既可以是信号名也可以是信号名对应的数字。-p:指定kill命令只显示命名进程的pid,并不真正送出任何信号。-l:显示信号名称列表,该列表也可以在/usr/include/linux/signal.h文件中找到。,系统监视,系统监控命令top:能显示实时的进程列表,而且还能实时监视系统资源,包括内存、交换分区和CPU的使用率等

7、。,5.2.2 Linux进程的结构,1task_struct结构task_struct结构包含下列几方面的信息:进程状态 调度信息 标志符(pid)内部进程通讯 链接信息 时间和计时器 文件系统 虚拟内存 处理器信息,2进程系统堆栈每个进程都有一个系统堆栈,用来保存中断现场信息和进程进入内核模式后执行子程序(函数)嵌套调用的返回现场信息。每个进程的系统堆栈和task_struct数据结构之间存在紧密联系,因而二者物理存储空间也连在一起 系统堆栈的大小静态确定,用户堆栈可在运行时动态扩展,5.2.3 对进程的操作,1进程的创建各个进程构成了树形的进程族系 内核在引导并完成了基本的初始化以后,就

8、有了系统的第一个进程init(即初始化进程,实际上是内核线程)。除此之外,所有其他的进程和内核线程都由这个原始进程或其子孙进程所创建。除初始化进程外,其他进程都是用系统调用fork()和clone()创建的。fork()是全部复制,而clone()有选择地复制,1.fork函数,fork系统调用的作用是复制一个进程。当一个进程调用它,完成后就出现两个几乎一模一样的进程,我们也由此得到了一个新进程。在Linux 中,创造新进程的方法只有一个,就是fork。其他一些库函数,如system(),看起来似乎它们也能创建新的进程,实际上也在内部调用了fork。包括我们在命令行下运行应用程序,新的进程也是

9、由shell调用fork制造出来的。,1.fork函数,/*example_fork.c*/#include#inlcudemain()pid_t pid;/*此时仅有一个进程*/pid=fork();/*此时已经有两个进程在同时运行*/if(pid0)printf(error in fork!);else if(pid=0)printf(I am the child process,my process ID is%dn,getpid();elseprintf(I am the parent process,my process ID is%dn,getpid();,1.fork函数,在语句

10、pid=fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了,这两个进程的代码部分完全相同,将要执行的下一条语句都是if(pid=0)。两个进程中,原先就存在的那个被称作“父进程”,新出现的那个被称作“子进程”。父子进程的区别除了进程标志符(process ID)不同外,变量pid的值也不相同,pid存放的是fork的返回值。fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:在父进程中,fork返回新创建子进程的进程ID;在子进程中,fork返回0;如果出现错误,fork返回一个负值;fork出错可能有两种原因:(1)当

11、前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。(2)系统内存不足,这时errno的值被设置为ENOMEM。,2.getpid和getppid函数,#include#include pid_t getpid(void);pid_t getpgrp(void);pid_t getppid(void);说明:分别返回调用进程的进程标识符、进程组标识符和其父进程标识符。,2进程的等待父进程可用系统调用wait()等待它的任一个子进程终止,也可以用系统调用wait()等待某个特定的子进程终止。wait()算法如下:(1)如果父进程没有子进程,则出错返回。(2)如果发现有一个

12、终止的子进程,则取出子进程的进程号,把子进程的CPU使用时间等加到父进程上,释放子进程占用的task_struct和系统空间堆栈,以供新进程使用。(3)如果发现有子进程,但都不处于终止态,则父进程睡眠,等待由相应的信号唤醒。,5.wait和waitpid函数,#include#include pid_t wait(int*status);pid_t waitpid(pid_t pid,int*status,int options);一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但它的PCB还保留着,内核在其中保存了一些信息:如果是正常终止则保存着退出状态,如果是异常终止则保存

13、着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程。如果一个进程已经终止,但是它的父进程尚未调用wait或waitpid对它进行清理,这时的进程状态称为僵尸(Zombie)进程。任何进程在刚终止时都是僵尸进程,正常情况下,僵尸进程都立刻被父进程清理了.如果一个父进程终止,而它的子进程还存在(这些子进程或者仍在运行,或者已经是僵尸进程了),则这些子进程的父进程改为init进程。,5.wait和waitpid函数,这两个函数的区别是:1.如果父进程的所有子进程都还在运行,调用wait将使父进程阻塞,而调用waitpid时如果在opti

14、ons参数中指定WNOHANG可以使父进程不阻塞而立即返回0。2.wait等待第一个终止的子进程,而waitpid可以通过pid参数指定等待哪一个子进程。可见,调用wait和waitpid不仅可以获得子进程的终止信息,还可以使父进程阻塞等待子进程终止,起到进程间同步的作用。如果参数status不是空指针,则子进程的终止信息通过这个参数传出,如果只是为了同步而不关心子进程的终止信息,可以将status参数指定为NULL。,5.wait和waitpid函数,对于waitpid函数中的pid参数的作用见下表:pid=-1 等待任一子进程。pid 0 等待其进程ID与pid相等的子进程pid=0 等待

15、其组ID等于调用进程组ID的任一的子进程pid-1 等待其组ID等于pid绝对值的任一的子进程对于waitpid函数中的options参数的作用见下表:WCONTINUED若实现支持作业控制,那么由pid指定的任一子进程在暂停后已经继续,但是状态没报告,则返回其状态WNOHANG若由pid指定的子进程并不是立即可用的,则waitpid不阻塞,此时返回值为0WUNTRACED若实现支持作业控制,那么由pid指定的任一子进程已经处于暂停状态并没报告过,则返回其状态,3进程的终止进程可使用系统调用exit()终止自己其实现算法如下:(1)撤消所有的信号量。(2)释放其所有的资源,包括存储空间、已打开

16、的文件、工作目录、信号处理表等。(3)置进程状态为“终止态”(TASK_ZOMBIE)。(4)向它的父进程发送子进程终止的信号。(5)执行进程调度。,4.exit和_exit函数,void exit(int status);void _exit(int status);exit()函数定义在 stdlib.h中,而_exit()定义在unistd.h中。_exit()函数的作用简单:直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构;exit()函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序。exit()函数与_exit()函数最大的区别就在于exit()函

17、数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件,就是图中的“清理I/O缓冲”一项。,4进程映像的更换改换进程映像的工作很复杂,是由系统调用execve()实现的,它用一个可执行文件的副本来覆盖该进程的内存空间。ELF可执行文件格式示意图 execve()系统调用的基本算法如下:(1)验证文件的可执行性,即用户 有权执行它。(2)读文件头,检查它是一个可装入模块。(3)释放原有的内存空间。(4)按照可执行文件的要求分配新的内存空间,并装入内存。,3.exec函数族,在Linux中,并不存在exec()函数,exec指的是一组函数,一共有6个,分别是:#includ

18、e extern char*environ;int execl(const char*path,const char*arg,.);int execlp(const char*file,const char*arg,.);int execle(const char*path,const char*arg,.,char*const envp);int execv(const char*path,char*const argv);int execvp(const char*file,char*const argv);int execve(const char*path,char*const arg

19、v,char*const envp);其中只有execve是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。exec函数族的作用是根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。这里的可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。,3.exec函数族,函数名与参数的关系:细看一下,这6个函数都是以exec开头(表示属于exec函数组),前3个函数接着字母l,后3个接着字母v。l表示list(列举参数),v表示vector(参数向量表)。它们的区别在于,execv开头的函数是以“char*argv”(

20、vector)形式传递命令行参数,而execl开头的函数采用了罗列(list)的方式,把参数一个一个列出来,然后以一个NULL表示结束。字母p是指在环境变量PATH的目录里去查找要执行的可执行文件。2个以p结尾的函数execlp和execvp,和execl与execv的差别很小,除execlp和execvp之外的4个函数都要求,它们的第1个参数path必须是一个完整的路径,如/bin/ls;而execlp和execvp的第1个参数file可以仅仅只是一个文件名,如ls,这两个函数可以自动到环境变量PATH指定的目录里去查找。字母e是指给可执行文件指定环境变量。在全部6个函数中,只有execle

21、和execve使用了char*envp传递环境变量,用指定的环境变量去替代默认的那些。,3.exec函数族,返回值 exec函数族的函数执行成功后不会返回,因为调用进程的实体,包括代码段,数据段和堆栈等都已经被新的内容取代,只有进程ID等一些表面上的信息仍保持原样。调用失败时,会设置errno并返回-1,然后从原程序的调用点接着往下执行。与其他系统调用比起来,exec很容易失败,被执行文件的位置、权限等很多因素都能导致调用失败。因此,使用exec函数族时,一定要加错误判断语句。最常见的错误:找不到文件或路径,此时errno被设置为ENOENT;数组argv和envp忘记用NULL结束,此时er

22、rno被设置为EFAULT;没有对要执行文件的运行权限,此时errno被设置为EACCES。,3.exec函数族,应用 如果一个进程想执行另一个程序,它就可以fork出一个新进程,然后调用任何一个exec函数。为此,Linux还专门对fork作了优化:通常fork会将调用进程的所有内容原封不动的拷贝到新产生的子进程中去,这些拷贝的动作很消耗时间,而如果fork完之后我们马上就调用exec,那这些辛辛苦苦拷贝来的东西就会被立刻抹掉,这看起来非常不划算,于是人们设计了一种写时复制(copy-on-write)技术,使得fork结束后并不立刻复制父进程的内容到子进程,而是到了真正使用时才复制,这样如

23、果下一条语句是exec,它就不会作无用功了。其实写时复制还是有复制,进程的mm结构、页表都还是被复制了。,3.exec函数族,例程/*example_exec.c*/#include void main(void)if(fork()=0)if(execl(/bin/echo,echo,executed by execl,NULL)0)if(execlp(echo,echo,executed by execlp,NULL)0)if(execle(/usr/bin/env,env,NULL,envp)0)if(execv(/bin/echo,argv_execv)0)if(execvp(echo,

24、argv_execvp)0)if(execve(/usr/bin/env,argv_execve,envp)0),5.2.4 进程调度,1调度方式:基本上采用“抢占式优先级”方式 2调度策略三种不同的调度策略 SCHED_FIFO短实时进程,对时间性要求比较强 SCHED_RR较长时间的实时进程,对应“时间片轮转法”SCHED_OTHER交互式的分时进程,这类进程的优先权取决于两个因素:一个因素是进程剩余时间配额;另一个是进程的优先数nice 优先数越小,其优先级越高 后台进程的优先级低于任何交互(前台)进程的优先级,3调度时机(1)当前进程调用系统调用nanosleep()或者pause()

25、,使自己进入睡眠状态,主动让出一段时间的CPU使用权。(2)进程终止,永久地放弃对CPU的使用。(3)在时钟中断处理程序执行过程中,发现当前进程连续运行的时间过长。(4)当唤醒一个睡眠进程时,发现被唤醒的进程比当前进程更有资格运行。(5)一个进程通过执行系统调用来改变调度策略或者降低自身的优先权(如nice命令),从而引起立即调度。4调度算法,6.sleep和nice函数,#include unsigned int sleep(unsigned int seconds);说明:进程挂起指定时间,直至用完或收到信号。#include int nice(int inc);说明:改变进程的优先级,5.2.5 shell基本工作原理,它不属于内核部分,而是在核心之外,以用户态方式运行。其基本功能是解释并执行用户打入的各种命令,实现用户与Linux核心的接口。,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 生活休闲 > 在线阅读


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号