实验2进程的控制一、实验目的通过进程的创建、撤消和运行加深对进程概念和进程并发执行的理解,明确进程与程序之间的区别。二、实验内容及步骤(1)了解系统调用fork()、execvp()、exit()和wait()的功能和实现过程。(2)编写一段程序,使用系统调用fork()来创建两个子进程,并由父进程重复显示字符串“parent:”和自己的标识数,而子进程则重复显示字符串“child:”和自己的标识数。(3)编写一段程序,使用系统调用fork()来创建一个子进程。子进程通过系统调用execvp()更换自己的执行代码,新的代码显示“newprogram.”后,调用exit()结束进程。而父进程则调用wait()等待子进程结束,并在子进程结束后显示子进程的标识符,然后正常结束。三、思考(1)系统调用fork()是如何创建进程的?(2)当首次将CPU调度给子进程时,其入口在哪里?(3)系统调用execvp()是如何更换进程的可执行代码的?(4)系统调用exit()是如何终止一个进程的?(5)对一个应用,如果用多个进程的并发执行来实现,与单个进程来实现有什么不同?实验步骤与调试过程:实验结果:1:Childidis3646Child2idis3647Parentidis36452:child'spid=2894child'spid=2994parent'spid=2849child'spid=2897child'spid=2897parent'spid=2849child'spid=2894child'spid=2994parent'spid=28493:newprogram!-ew-r--rr--1rootroot172109-0313:15/etc/passwdchildpeocessPID:3689疑难小结:主要算法和程序清单:1:#includestdio.hvoidmian(){intid;if(fork()==0){printf(childidis%d\n,getpid());}elseif(fork()==0){printf(child2id%d\n,getpid());}else{id=wait();printf(parentidis%d\n,getpid());}}2:#includeunistd.h#includestdio.hmain(){intp1,p2;while((p1=fork())==-1);if(p1==0)printf(child’spid=%d\n,getppid());else{while((p2=fork())==-1);if(p2==0)printf(child’spid=%d\n,getppid());elseprintf(parent’spid=%d\n,getppid());}}3:#includestdio.h#includestdlib.h#includesys/wait.hintmain(){pid_tpid;char*a[]={ls,-l,/etc/passwd,0};intresult;pid=fork();if(pid0)printf(frokerror!);elseif(pid==0)printf(newprogram!\n);execvp(ls,a);exit(0);}else{inte=waitpid(pid,&result,0);printf(childpeocessPID:%d\n,e);exit(0);}}1:2:3:实验3进程通信(一)一、实验目的学习如何利用管道机制、共享存储区机制进行进程间的通信,并加深对上述通信机制的理解。二、实验内容及步骤(1)了解系统调用pipe()、shmget()、shmat()、shmdt()、shmctl()的功能和实现过程。(2)编写一段程序,使其用管道来实现父子进程之间的进程通信。子进程向父进程发送自己的进程标识符,以及字符串“issendingamessagetoparent!”。父进程则通过管道读出子进程发来的消息,将消息显示在屏幕上,然后终止。(3)编写一段程序,使其用共享存储区来实现父子进程之间的进程通信。父进程创建一个长度为512字节的共享内存空间,显示写入该共享内存的数据;子进程将共享内存也附加到自己的地址空间,并向共享内存中写入数据。三、思考(1)上述哪个通信机制提供了发送进程和接收进程之间的同步功能?这些同步是如何进行的?(2)上述通信机制各有什么特点,它们分别适合于何种场合?1:2:实验目的:学习如何利用管道机制、共享存储区机制进行进程间的通信,并加深对上述通信机制的理解。实验内容:了解进程读写,fork(),管道通信的通;共享内存函数的at、shmdt、shmctl四个函数的作用和用法,了解系统调用pipe()、shmget()、shmat()、shmdt()、shmctl()的功能和实现过程;编写一段程序,使其用管道来实现父子进程之间的进程通信。子进程向父进程发送自己的进程标识符,以及字符串“issendingamessage”。父进程则通过管道读出子进程发来的消息,将消息显示在屏幕上,然后终止;编写一段程序,使其用共享存储区来实现父子进程之间的进程通信。父进程创建一个长度为512字节的共享内存空间,显示写入该共享内存的数据;子进程将共享内存也附加到自己的地址空间,并向共享内存中写入数据。实验步骤与调试过程:1.开辟一块共享内存shmget()2.允许本进程使用共某块共享内存shmat()3.写入/读出4.禁止本进程使用这块共享内存shmdt()5.删除这块共享内存shmctl()或者命令行下ipcrmfrok()。它有两个参数,一个是字符串,一个是字符。字符串一般用当前进程的程序名,字符一般用来标记这个标识符所标识的共享内存是这个进程所开辟的第几个共享内存。无名管道主要用于父进程与子进程之间,或者两个兄弟进程之间。在linux系统中可以通过系统调用建立起一个单向的通信管道,且这种关系只能由父进程来建立。因此,每个管道都是单向的,当需要双向通信时就需要建立起两个管道。管道两端的进程均将该管道看做一个文件,一个进程负责往管道中写内容,而另一个从管道中读取。这种传输遵循“先入先出”的规则。命名管道命名管道是为了解决无名管道只能用于近亲进程之间通信的缺陷而设计的。命名管道是建立在实际的磁盘介质或文件系统(而不是只存在于内存中)上有自己名字的文件,任何进程可以在任何时间通过文件名或路径名与该文件建立联系。为了实现命名管道,引入了一种新的文件类型——FIFO文件(遵循先进先出的原则)。实现一个命名管道实际上就是实现一个FIFO文件。命名管道一旦建立,之后它的读、写以及关闭操作都与普通管道完全相同。虽然FIFO文件的inode节点在磁盘上,但是仅是一个节点而已,文件的数据还是存在于内存缓冲页面中,和普通管道相同。1.shmget(得到一个共享内存标识符或创建一个共享内存对象,得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符)所需头文件:#includesys/ipc.h,#includesys/shm.h2.shmat函数原型shmat(把共享内存区对象映射到调用进程的地址空间)所需头文件#includesys/types.h,#includesys/shm.h连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问函数原型3.shmdt函数原型shmat(断开共享内存连接)所需头文件#includesys/types.h,#includesys/shm.h与shmat函数相反,是用来断开与共享内存附加点的地址,禁止本进程访问此片共享内存4.shmctl函数原型shmctl(共享内存管理)所需头文件#includesys/types.h,#includesys/shm.h完成对共享内存的控制实验结果:编译gcc1.c-o1./1结果为:1:9342issendingmessage!9342issendingmessage!编译gcc2.c-o2./2结果为:2:3005issendingmessagetoparent3005issendingmessagetoparent主要算法和程序清单:1:#includestdio.h#includestdlib.h#includestring.h#includesys/shm.hintmain(){intfd[2];charstr[512];if(pipe(fd)0){printf(error!\n);exit(0);}if(fork()==0){sprintf(str,%dissendingmessage!,getpid());printf(%s\n,str);write(fd[1],str,sizeof(str));}else{wait(0);read(fd[0],str,sizeof(str));printf(%s\n,str);}return0;}2:#includestdio.h#includestdlib.h#includestring.h#includesys/shm.h#defineSHMKEY75intmain(){intid;char*ad;charstr[512];id=shmget(SHMKEY,512,0777|IPC_CREAT);if(fork()==0){sprintf(str,%dissendingmessagetoparent,getpid());print(%s\n,str);ad=shmat(id,0,0);strcpy(ad,str);shmdt(ad);}else{wait(0);ad=shmat(id,0,0);printf(%s\n,ad);shmdt(ad);shmctl(id,IPC_RMID,0);}return0;}实验4进程通信(二)一、实验目的学习如何利用消息缓冲队列进行进程间的通信,并加深对消息缓冲队列通信机制的理解。二、实验内容及步骤(1)了解系统调用msgget()、msgsnd()、msgrcv()、msgctl()的功能和实现过程。(2)编写一段程序,使其用消息缓冲队列来实现父进程和子进程之间的通信。父进程先建立一个关键字为MSGKEY(如75)(即#defineMSGKEY75)的消息队列,然后等待接收类型为1的消息;在收到请求消息后,它便显示字符串“servingforclient”和接收到的子进程的进程标识数,表示正在为子进程服务;然后再向子进程发送一应答消息,该消息的类型是该子进程的进程标识数,而正文则是父进程自己的标识数。子进程则向消息队列发送类型为1的消息(消息的正文为自己的进程标识数),以取得父进程的服务,并等待父进程发来的应答;然后显示字符串“receivereplyfrom”和接收到的父进程的标识数。消息的结构为:structmsgform{longmtype;//消息类型charmtext[1024];//消息正文};三、思考(1)消息缓冲机制是否提供了发送进程和接收进程之间的同步功能?同步是如何进行的?(2)消息缓冲机制有什么特点,它适合于何种场合?实验步骤与调试过程:实验结果:4610servingforclient4610receivefrom4609疑难小结:主要算法和程序清单:#includestdio.h#includesys/msg.h#defineMKEY75structmsgform{longmid;charmtext[1024];};intmain(){intid;structmsgformmsg;id=msgget(MKEY,0777|IPC_CREAT);if(fork()==0){msg.mid=1;sprintf(msg.mtext,%d,getpid());pri