操作系统实验实验5 进程管理课件

上传人:我*** 文档编号:141782917 上传时间:2020-08-12 格式:PPT 页数:31 大小:395KB
返回 下载 相关 举报
操作系统实验实验5 进程管理课件_第1页
第1页 / 共31页
操作系统实验实验5 进程管理课件_第2页
第2页 / 共31页
操作系统实验实验5 进程管理课件_第3页
第3页 / 共31页
操作系统实验实验5 进程管理课件_第4页
第4页 / 共31页
操作系统实验实验5 进程管理课件_第5页
第5页 / 共31页
点击查看更多>>
资源描述

《操作系统实验实验5 进程管理课件》由会员分享,可在线阅读,更多相关《操作系统实验实验5 进程管理课件(31页珍藏版)》请在金锄头文库上搜索。

1、实验五 Linux进程管理,进程的一生,实验目的 熟悉进程及进程控制等基本概念在Linux操作系统中的实现 利用Linux提供的系统调用函数/库函数实现进程管理 实验准备及预习 阅读讲义附件6, Linux进程管理,理解进程在其生命周期中的主要状态及有关操作命令和函数:ps、fork()、exit()、sleep()和wait(),进程简介,问题1:单CPU计算机上在一个时间片断内只能执行一条指令,那么Linux是如何实现多进程同时执行的呢? Linux使用了一种称为“进程调度(process scheduling)”的手段 为每个进程指派一定的运行时间(这个时间通常很短,通常以毫秒为单位),

2、然后依照某种规则,从众多进程中挑选一个投入运行,其他的进程暂时等待 当正在运行的那个进程时间耗尽,或执行完毕退出,或因某种原因暂停,Linux就会重新进行调度,挑选下一个进程投入运行 每个进程占用的时间片都很短,从使用者的角度来看,就好像多个进程同时运行一样,在Linux中,每个进程在创建时都会被分配一个数据结构,称为进程控制块(Process Control Block,简称PCB),PCB中包含了很多重要的信息,供系统调度和进程本身执行使用,其中最重要的莫过于进程ID(process ID) 进程ID也被称作进程标识符,是一个非负的整数,在Linux操作系统中唯一地标志一个进程,在最常使用

3、的i386架构(即PC使用的架构)上,一个非负的整数的变化范围是0-32767,这也是所有可能取到的进程ID 从进程ID的名字可看出,它是进程的身份证号码,每个进程的进程ID不会相同,ps命令,ps命令的常用选项 l:以长格式显示进程信息 ef:显示系统中所有进程的全面信息 aux:显示所有终端上所有用户进程的所有信息,ps命令是查看进程状态的最常用的命令,可以提供关于进程的许多信息。根据显示的信息可以确定哪个进程正在运行、哪个进程被挂起、进程已运行多长时间、进程正在使用的资源、进程的相对优先级,以及进程的标识号(PID)等信息,ps命令各输出项的含义为: S(state):进程状态,其中R表

4、示运行状态;S表示休眠状态;T表示暂停或终止状态;Z表示僵死状态 UID(User ID):进程启动者的用户ID PID(ProcessID):进程号 PPID:父进程的进程号 NI(Nice):进程的优先级值 SZ(Size):进程占用内存空间的大小,以KB为单位 TTY:进程所在终端的终端号,其中桌面环境的终端窗口表示为pts/0,字符界面的终端号为tty1tty6. TIME:进程累计使用的CPU时间 CMD:启动进程的shell命令,fork,2.4.4版内核中,fork是第2号系统调用,函数库中的原型是: #include /* 提供类型pid_t的定义 */ #include /*

5、 提供函数的定义 */ pid_t fork(void);,fork系统调用的作用是复制一个进程。当一个进程调用它,完成后就出现两个几乎一模一样的进程,由此得到了一个新进程 Linux中创造新进程的方法只有fork系统调用,其他一些看起来似乎也能创建新进程库函数,实际上也在内部调用了fork;包括在命令行下运行应用程序,新进程也是由shell调用fork制造出的,问题2:如果fork后子进程和父进程几乎完全一样,而系统中产生新进程的唯一方法就是fork,那系统中所有的进程都要一模一样吗?如果子进程要执行新的应用程序怎么办?,例1,在Linux系统中运行下面程序,最多可产生多少个进程?画出进程家

6、族树。 int main() fork(); fork(); fork(); ,分析,向下,父进程A int main() fork(); fork(); fork(); ,子进程 B int main() fork(); fork(); fork(); ,子进程 C int main() fork(); fork(); fork(); ,子进程 F int main() fork(); fork(); fork(); ,子进程 E int main() fork(); fork(); fork();,子进程H int main() fork(); fork(); fork(); ,子进程 D

7、 int main() fork(); fork(); fork(); ,子进程 G int main() fork(); fork(); fork(); ,返回,#include int main() int p1, p2, i; while(p1=fork()= -1); if(p1=0) for(i=0;i3;i+) printf(“child %dn”, p1); printf(“child %d is interrupted, press enter to continue:n”,p1); getchar(); for(i=0;i3;i+) printf(“child %dn”, p

8、1); else while(p2=fork()= -1); if(p2=0) for(i=0;i3;i+) printf(“child %dn”, p2); printf(“child %d is interrupted, press enter to continue:n”,p2); getchar(); for(i=0;i3;i+) printf(“child %dn”, p2); else for(i=0;i3;i+) printf(“parentn”); printf(“father is interrupted, press enter to continue:n”); getch

9、ar(); for(i=0;i3;i+) printf(“parentn”); return 0; ,例2,问题3:如何修改程序,使得在各进程的输出信息中能显示自己的进程号?,getpid,2.4.4版内核中,getpid是第20号系统调用,其Linux函数库中的原型是: #include /* 提供类型pid_t的定义 */ #include/* 提供函数的定义 */ pid_t getpid(void); getpid的作用很简单,即返回当前进程的ID,请看的例子: /* getpid_test.c */ #include main() printf(The current process

10、 ID is %dn,getpid(); ,编译并运行程序getpid_test.c: $gcc -o getpid_test getpid_test.c $./getpid_test The current process ID is 1980 再运行一遍: $./getpid_test The current process ID is 1981,自己的运行结果很可能与这个数字不一样,这很正常,尽管是同一个程序,每次运行所分配到的进程标识符都不相同,exit,2.4.4版内核中exit是第1号调用,原型是: #include void exit(int status); exit用来终止一

11、个进程。无论在程序中的什么位置,只要执行到exit系统调用,进程就会停止剩下的所有操作,清除包括PCB在内的各种数据结构,并终止本进程的运行,/* exit_test1.c */ #include main() printf(this process will exit!n); exit(0); printf(never be displayed!n); 编译后运行: $gcc -o exit_test1 exit_test1.c $./exit_test1 this process will exit!,程序并没有打印never be displayed!/n,因为在此之前,在执行到exit

12、(0)时,进程就已经终止了,exit系统调用带有一个整型参数status,可利用这个参数传递进程结束时的状态,例如该进程是正常结束/出现某种意外而结束 一般地,0表示没有意外的正常结束;其他的数值表示出现了错误,进程非正常结束 编程时,可用wait系统调用接收子进程的返回值,从而针对不同的情况进行不同的处理,exit和_exit,_exit在Linux函数库中的原型是: #include void _exit(int status); 作为系统调用,_exit和exit是一对孪生兄弟 _exit()函数最为简单:直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构 exit

13、()函数则在这些基础上作了一些包装,在执行退出之前加了若干道工序,两者间的最大区别:exit()函数在调用exit系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件 Linux标准函数库中,有一套称作“高级I/O”的函数(printf()、fopen()、fread()、fwrite()都在此列),也称作“缓冲I/O)” 对应每一个打开的文件,在内存中都有一片缓冲区,每次读文件时,会多读出若干条记录,这样下次读文件时就可以直接从内存的缓冲区中读取,每次写文件的时候,也仅仅是写入内存中的缓冲区,等满足了一定的条件(达到一定数量,或遇到特定字符,如换行符/n和文件结束符EOF),再将缓

14、冲区中的内容一次性写入文件,因此极大地增加了文件读写速度 为编程带来了一点点麻烦:可能存在某些数据,我们认为已写入文件,实际上因为没有满足特定的条件,只是保存在缓冲区内,这时如果使用_exit()函数直接关闭进程,缓冲区中的数据就会丢失 如果想保证数据的完整性,请使用exit()函数,/* exit2.c */ #include main() printf(output beginn); printf(content in buffer); exit(0); 编译并运行: $gcc -o exit2 exit2.c $./exit2 output begin content in buffer

15、,/* _exit1.c */ #include main() printf(output beginn); printf(content in buffer); _exit(0); 编译并运行: $gcc -o _exit1 _exit1.c $./_exit1 output begin,Linux将标准IO作为文件处理,虽然是一类特殊文件,但从程序员的角度来看,和硬盘上的普通文件并无区别,与所有其他文件一样,打开后也有自己的缓冲区,问题4:为什么两个程序的执行结果不同?,僵尸进程,进程调用exit后,进程并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构 在Linux进程

16、的5种状态中,僵尸进程是非常特殊的一种:已放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集 当一个进程已退出,但其父进程还没有调用系统调用wait(稍后介绍)对其进行收集之前的这段时间里,它会一直保持僵尸状态,/* zombie.c */ #include #include main() pid_t pid; pid=fork(); if(pid0) /* 出错处理 */ printf(error occurred!n); else if(pid=0) /*子进程 */ exit(0); else /* 父进程 */ sleep(60);/* 休眠60秒,父进程放弃CPU */ wait(NULL); /* 收集僵尸进程 */ ,sleep的作用是让进程休眠,期间子进程已退出,而父进程正忙着睡觉,不可能对它进行收集,使得子进程能保持60秒的僵尸状态,编译程序: $

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 办公文档 > PPT模板库 > PPT素材/模板

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号