《2022年北邮-大三-操作系统-进程管理实验报告 .pdf》由会员分享,可在线阅读,更多相关《2022年北邮-大三-操作系统-进程管理实验报告 .pdf(12页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、1/12 实验一进程管理1实验目的:(1)加深对进程概念的理解,明确进程和程序的区别;(2)进一步认识并发执行的实质;(3)分析进程争用资源的现象,学习解决进程互斥的方法;(4)了解 Linux 系统中进程通信的基本原理。2实验预备内容(1)阅读 Linux 的 sched.h源码文件,加深对进程管理概念的理解;(2)阅读 Linux 的 fork()源码文件,分析进程的创建过程。3实验内容(1)进程的创建:编写一段程序,使用系统调用fork()创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示字符“a”,子进程分别显示字符“b”
2、和“c”。试观察记录屏幕上的显示结果,并分析原因。源代码如下:#include#include#include#include#include int main(int argc,char*argv)pid_t pid1,pid2;pid1=fork();if(pid10)fprintf(stderr,childprocess1 failed);exit(-1);名师资料总结-精品资料欢迎下载-名师精心整理-第 1 页,共 12 页 -2/12 else if(pid1=0)printf(bn);else pid2=fork();if(pid20)fprintf(stderr,childpro
3、cess1 failed);exit(-1);else if(pid2=0)printf(cn);else printf(an);sleep(2);exit(0);return 0;结果如下:分析原因:pid=fork();操作系统创建一个新的进程(子进程),并且在进程表中相应为它建名师资料总结-精品资料欢迎下载-名师精心整理-第 2 页,共 12 页 -3/12 立一个新的表项。新进程和原有进程的可执行程序是同一个程序;上下文和数据,绝大部分就是原进程(父进程)的拷贝,但它们是两个相互独立的进程!因此,这三个进程哪个先执行,哪个后执行,完全取决于操作系统的调度,没有固定的顺序。(2)进程的控
4、制修改已经编写的程序,将每个进程输出一个字符改为每个进程输出一句话,再观察程序执行时屏幕上出现的现象,并分析原因。将父进程的输出改为father process completed 输出 b 的子进程改为输出child process1 completed 输出 c 的子进程改为输出child process2 completed 运行的结果如下:理由同(1)如果在程序中使用系统调用lockf()来给每一个进程加锁,可以实现进程之间的互斥,观察并分析出现的现象。加锁之后的代码:#include#include#include#include#include int main(int argc,
5、char*argv)pid_t pid1,pid2;pid1=fork();if(pid10)fprintf(stderr,childprocess1 failed);exit(-1);名师资料总结-精品资料欢迎下载-名师精心整理-第 3 页,共 12 页 -4/12 else if(pid1=0)lockf(1,1,0);printf(child process1 completedn);else pid2=fork();if(pid20)fprintf(stderr,childprocess1 failed);exit(-1);else if(pid2=0)lockf(1,1,0);pri
6、ntf(child process2 completedn);else lockf(1,1,0);printf(“father process is completedn”);sleep(2);exit(0);return 0;名师资料总结-精品资料欢迎下载-名师精心整理-第 4 页,共 12 页 -5/12 所谓进程互斥,是指两个或两个以上的进程,不能同时进入关于同一组共享变量的临界区域,否则可能发生与时间有关的错误,这种现象被称作进程互斥.lockf()函数是将文件区域用作信号量(监视锁),或控制对锁定进程的访问(强制模式记录锁定)。试图访问已锁定资源的其他进程将返回错误或进入休态,直到资
7、源解除锁定为止。而上面三个进程,不存在要同时进入同一组共享变量的临界区域的现象,因此输出和原来相同。(3)a)编写一段程序,使其实现进程的软中断通信。要求:使用系统调用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即按DEL 键);当捕捉到中断信号后,父进程用系统调用Kill()向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止:Child Process 1 is killed by Parent!Child Process 2 is killed by Parent!父进程等待两个子进程终止后,输出如下的信息后终止:Parent Pro
8、cess is killed!代码如下:#include#include#include#include#include#include int wf;void waiting()while(wf!=0);名师资料总结-精品资料欢迎下载-名师精心整理-第 5 页,共 12 页 -6/12 void stop()wf=0;int main(int argc,char*argv)pid_t pid1,pid2;pid1=fork();if(pid10)fprintf(stderr,childprocess1 failed);exit(-1);else if(pid1=0)wf=1;signal(1
9、6,stop);/捕捉到父进程传来的16 信号,继续往下执行waiting();/不往下执行lockf(1,1,0);printf(Child Process 1 is killed by Parent!n);lockf(1,0,0);exit(0);else 名师资料总结-精品资料欢迎下载-名师精心整理-第 6 页,共 12 页 -7/12 pid2=fork();if(pid20)fprintf(stderr,childprocess1 failed);exit(-1);else if(pid2=0)wf=1;signal(17,stop);/捕捉到父进程传来的17 信号,继续往下执行wa
10、iting();/不往下执行lockf(1,1,0);printf(Child Process 2 is killed by Parent!n);lockf(1,0,0);exit(0);else wf=1;/wf为 1时,不往下执行,直到捕捉到键盘上传来的信号signal(SIGINT,stop);/捕捉到键盘传来的信号,执行stop 函数waiting();kill(pid1,16);/向子进程p1 发软中断信号 16 kill(pid2,17);/向子进程 p2 发软中断信号17 wait(0);名师资料总结-精品资料欢迎下载-名师精心整理-第 7 页,共 12 页 -8/12 wait
11、(0);printf(Parent Process is killed!n);exit(0);return 0;按下 ctrl+c后,运行结果如下:软中断一般是指由指令int引起的“伪”中断动作给CPU制造一个中断的假象;而硬中断则是实实在在由8259 的连线触发的中断。kill函数的原型如下:int kill(pid,sig),pid 是一个或一组进程的标识符,参数sig 是要发送的软中断信号。signal函数的原型如下:signal(sig,function),它以软中断信号的序号作为参数调用函数,也就是说,收到软中断信号sig后,调用函数function.当子进程1 收到软中断信号16
12、时,调用函数stop()解除“waiting”,继续往下执行;等它打印完了child process 1 is killed by parent,就退出;对于子进程2 来说也是如此。而父进程在此阶段一直处于“waiting”状态(执行wait(0),直到两个子进程都退出了,父进程才会退出。由于 ctrl+c 信号会并发传到每个进程中,进程受到该信号会立刻终止。当子进程收到ctrl+c 信号时,就终止了,根本不会等父进程传来的软中断信号,因此也就不会打印出child process1 is killed 和 child process2 is killed.b)在上面的程序中增加语句signal
13、(SIGINT,SIG-IGN)和 signal(SIGQUIT,SIG-IGN),观察执行结果,并分析原因。按下 ctrl+c后,运行结果如下:signal(SIGINT,SIG-IGN)和 signal(SIGQUIT,SIG-IGN)的作用是屏蔽从键盘上传来的中断信号,因此子进程可以接收到父进程传来的软中断信号,进而将那两句话打印出来名师资料总结-精品资料欢迎下载-名师精心整理-第 8 页,共 12 页 -9/12(4)进程的管道通信编制一段程序,实现进程的管道通信。使用系统调用pipe()建立一条管道线;两个子进程P1 和 P2分别向管道各写一句话:Child 1 is sending
14、 a message!Child 2 is sending a message!而父进程则从管道中读出来自于两个子进程的信息,显示在屏幕上。要求父进程先接收子进程P1 发来的消息,然后再接收子进程P2 发来的消息。源代码如下:#include#include#include#include#include int main(int argc,char*argv)pid_t pid1,pid2;int fd2;char parbuf50,childbuf50;pipe(fd);/建立管道pid1=fork();if(pid10)fprintf(stderr,childprocess2 faile
15、d);exit(-1);else if(pid1=0)lockf(fd1,1,0);sprintf(childbuf,Child 2 is sending a message!n);write(fd1,childbuf,50);/向管道中写东西sleep(5);名师资料总结-精品资料欢迎下载-名师精心整理-第 9 页,共 12 页 -10/12 lockf(fd1,0,0);exit(0);else pid2=fork();if(pid20)fprintf(stderr,childprocess1 failed);exit(-1);else if(pid2=0)lockf(fd1,1,0);s
16、printf(childbuf,Child 1 is sending a message!n);write(fd1,childbuf,50);/向管道中写东西sleep(5);lockf(fd1,0,0);exit(0);else wait(0);/等待某个子进程结束read(fd0,parbuf,50);/从管道中读东西printf(%s,parbuf);wait(0);/等待某个子进程结束read(fd0,parbuf,50);/从管道中读东西printf(%s,parbuf);exit(0);return 0;名师资料总结-精品资料欢迎下载-名师精心整理-第 10 页,共 12 页 -1
17、1/12 运行结果如下:值得注意的是,pipe(fd);pid1=fork();这两句的位置不能调换,否则会出现下面结果:也就是说,只有子进程1 向通过管道向父进程发送信息,且程序一直不退出。用 strace命令追查,可发现如果先 fork,那么在 fork 之后就是两个独立的进程,在两个独立进程中分别调用 pipe得到的是两个独立的fd 数组,向子进程的fd1 写 入,从父进程的fd0读取,父进程会堵在read上,因为根本就没有进程在写父进程的fd1。4思考(1)系统是怎样创建流程的?系统通过调用 fork 函数创建进程,当一个 进程调用了 fork 以后,系统会创建一个子 进程.这个子进程
18、和父 进程不同的地方只有他的 进程 ID 和父 进程 ID,其他的都是一 样.就象符 进程 克隆(clone)自己一 样.而此 时子进程也与父 进程分道扬镳,各自 执行自己的操作。至于先执行子进程,还是先执行父进程,取决去内核的 调度算法。一旦子 进程被创建,父子 进程相互 竞争系统的资源.有时候我们希望子 进程继续执 行,而父 进程阻塞直到子 进程完成任 务.这个时候我们可以调用 wait 或者 waitpid系统调用.(2)可执行文件加载时进行了哪些处理?注册一个可执行文件的加载模块(包含信息:链表list,所属的 module,加载可执行文件,加载共享库),然后遍历链表,依次按modul
19、e加载这个可执行文件(3)当首次调用新创建进程时,其入口在哪里?在进程队列的 ready 状态下,由离自己最近的父 进程执行调度,即入口在最近的父 进程处。(4)进程通信有什么特点?(针对管道通信)名师资料总结-精品资料欢迎下载-名师精心整理-第 11 页,共 12 页 -12/12 只支持 单向数据流;只能用于具有 亲缘关系的 进程之间;没有名字;管道的缓冲区是有限的(管道制存在于内存中,在管道创建时,为缓冲区分配一个页面大小);管道所传送的是无格式字节流,这就要求管道的读出方和写入方必须事先约定好数据的格式,比如多少字节算作一个消息(或命令、或记录)等等;总结通过这次实验,让我对操作系统进
20、程这一章的内容有了更深入的理解。此次实验有四部分组成。第一部分的重点是进程创建。在linx 操作系统中,进程的创建需要调用fork 函数。此函数调用一次,返回两次。第二部分的重点进程互斥。所谓的进程互斥,是指两个或两个以上的进程,不能同时进入关于同一组共享变量的临界区域。通过编程,能更加理解这个概念。进程互斥通过lockf()来实现。第三部分的重点是通过 kill()函数和 signal()函数深入理解进程的之间的软中断。前者是发送软中断信号,后者是接收软中断信号。第四部分的重点是通过 pipe()函数理解进程之间的管道通信。此次实验,还让我学到了一些调试方法。其中一个就是strace,即追查程序中的函数调用。在管道通信中,fork()和 pipe()这个函数的顺序不能随意调换。调换了之后引起的问题(程序一直不退出)可以用strace命令来追查,发现是父进程block在 read()上面,即父进程不知道从哪里读取信息。进而再通过查阅资料可知,是 fork()和 pipe()函数的顺序问题。名师资料总结-精品资料欢迎下载-名师精心整理-第 12 页,共 12 页 -