操作系统实验报告09070010吴嵩实验二进程管理一、实验目的加深对进程概念的理解,明确进程与程序的区别;进一步认识并发执行的实质二、实验内容进程的管道通信编写程序实现进程的管道通信。使用系统调用pipe()建立一个管道,二个子进程P1和P2分别向管道各写一句话:Child1issendingamessage!Child2issendingamessage!父进程从管道中读出二个来自子进程的信息并显示(要求先接收P1,再接收P2)。三、实验要求按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。四、实验设计建立一个管道。在程序中先建立一个子进程,然后向管道中输入数据,然后从子进程中退出到父进程,读出管道数据,然后再建立一个子进程,写入数据,再读出,即可。代码如下:#includestdio.h#includesys/types.h#includeunistd.hvoidmain(){intfd[2];pid_tpid,pid1;charbuf[256];intrc;pipe(fd);if((pid=fork())0){printf(Errorinfork\n);exit(1);}if(pid==0){close(fd[0]);write(fd[1],Child1issendingamessage,strlen(Child1issendingamessage));exit(0);}else{rc=read(fd[0],buf,sizeof(buf));printf(%dbytesofdatareceivedfromspawnedprocess:%s\n,rc,buf);if((pid1=fork())0){printf(Errorinfork\n);exit(1);}if(pid1==0){close(fd[0]);write(fd[1],Child2issendingamessage,strlen(Child2issendingamessage));exit(0);}else{close(fd[1]);rc=read(fd[0],buf,sizeof(buf));printf(%dbytesofdatareceivedfromspawnedprocess:%s\n,rc,buf);}}}五、运行结果六、感想及分析此次实验让我对进程和管道有了进一步的理解,用fork()创建完子进程后,要用exit()返回父进程,当需要创建两个子进程的时候,不能直接在第一个子进程中直接fork(),要返回到父进程再用fork()再次创建子进程,否则将无法控制。创建完管道后,在向管道中写入数据和从管道中读出数据的时候,要控制好管道的读写控制,不适当的关闭和开启管道端口,将不能使得数据得到正确的读写。这些是我此次实验最大的收获,还需要在今后的时候发现更多的问题,有更深的理解。七、参考资料《2011秋季实验指导》实验三一个进程启动另一个程序的执行一、实验目的编写Linux环境下,fork()与exec()的结合使用实现一个进程启动另一个程序的执行的基本方法,掌握exec()的集中调用方法。二、实验内容父进程从终端读取要执行的命令,并交给子进程执行。父进程等待子进程结束,并打印子进程的返回值。提示:从终端读取要执行的命令可用fgets()实现。三、实验要求按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。四、实验设计定义一个字符数组来放置命令字符,并用fgets()来实现读取用户输入的命令字符并存入字符数组。用if来判断当用户输入”quit”时,退出当时程序。子程序中调用execlp(),执行成功的话不返回,失败的话返回个-1,并将失败原因打印出来。在父进程中wait等到子进程执行完,然后打印出子进程的返回值。代码如下:#includestdio.h#includestring.h#includeunistd.h#includestdlib.h#includeerrno.h#includesys/types.h#includesys/wait.hcharcommand[256];intmain(){intrtn;interrorno;while(1){printf();fgets(command,256,stdin);/*从终端读取命令*/command[strlen(command)-1]=0;if(!strcmp(command,quit)){break;}/*当输出quit时退出程序*/if(fork()==0){/*子进程执行此命令*/errorno=execlp(command,command,NULL,NULL);/*如果exec函数返回,表明没有正常执行命令,打印错误信息*/perror(command);exit(errorno);}else{/*父进程,等待子进程结束,并打印子进程的返回值*/wait(&rtn);printf(childprocessreturn%d\n,rtn);}}return0;}五、运行结果六、感想及分析此次实验让我对exec类的函数有了一个更深的理解,我知道一个进程一旦调用exec类函数,它本身就“死亡”了,系统把代码段替换成新的程序的代码,废弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一留下的,就是进程号,也就是说,对系统而言,还是同一个进程,不过已经是另一个程序了。同时也学会了fgets()的用法。我写的程序运行后输入命令是不带参数的,由于execlp是这么定义的:intexeclp(constchar*file,constchar*arg,……);其中找到符合参数file的文件后,第二个之后的参数当做该文件的argv[0],argv[1]…..所以在程序execlp中的后面加入相应的参数即可。七、参考资料《2011秋季实验指导》实验四基于消息队列和共享内存的进程间通信一、实验目的Linux系统的进程通信机构(IPC)允许在任意进程间大批量地交换数据。本实验的目的是了解和熟悉:1.Linux支持的消息通信机制及其使用方法2.Linux系统的共享存储区的原理及使用方法。二、实验内容1.消息的创建、发送和接收使用消息调用msgget()、msgsnd()、msggrev()、msgctrl()编制长度为1K的消息的发送和接收程序。2.共享存储区的创建、附接和断接使用系统调用shmget()、shmat()、shmctl(),编制一个与上述功能相同的程序。三、实验要求按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。四、实验设计1.消息队列:先定义一个消息结构,包含消息类型和文本长度。在SERVER函数中,首先获得一个KEY为75的消息的描述符,然后利用dowhile循环来判断当消息类型为1的时候打印输出。在CLIENT函数中,先获得消息队列,然后利用for循环将消息类型从10赋值到1,发送队列,并打印输出。最后在main函数中调用这两个函数。代码如下:#includestdio.h#includesys/types.h#includesys/msg.h#includesys/ipc.h#defineMSGKEY75structmsgform/*消息结构*/{longmtype;/*消息类型*/charmtexe[1030];/*文本长度*/}msg;intmsgqid,i;voidCLIENT(){inti;msgqid=msgget(MSGKEY,0777);/*获得消息的描述符msgqid*/for(i=10;i=1;i--)/*将消息类型由10到1发送*/{msg.mtype=i;printf((client)sent\n);msgsnd(msgqid,&msg,1024,0);/*发送消息msg入msgid消息队列*/}exit(0);}voidSERVER(){msgqid=msgget(MSGKEY,0777|IPC_CREAT);do{msgrcv(msgqid,&msg,1030,0,0);/*从队列msgid接受消息msg*/printf((server)receive\n);}while(msg.mtype!=1);/*消息类型为1时,释放队列*/msgctl(msgqid,IPC_RMID,0);exit(0);}main(){if(fork())SERVER();elseCLIENT();wait(0);wait(0);}2.共享存储区:先获取共享区,KEY为75,并获得描述符,然后将该共享存储区附接到addr这个虚拟地址上,如消息队列类似,利用while循环从10到1打印输出,并将i值赋给addr。在SERVER中,创建共享存储区,并将起始地址也设置为addr,服务进程共享存储区,所以直接用while循环输出打印“receive”。代码如下:#includesys/types.h#includesys/msg.h#includesys/ipc.h#defineSHMKEY75/*定义共享区关键词*/intshmid,i;int*addr;CLIENT(){inti;shmid=shmget(SHMKEY,1024,0777);/*获取共享区*/addr=shmat(shmid,0,0);/*共享区起始地址为addr*/for(i=9;i=0;i--){while(*addr!=-1);printf((client)sent\n);*addr=i;}exit(0);}SERVER(){shmid=shmget(SHMKEY,1024,0777|IPC_CREAT);addr=shmat(shmid,0,0);do{*addr=-1;/*服务进程使用共享区*/while(*addr==-1);printf((server)received\n);}while(*addr);shmctl(shmid,IPC_RMID,0);exit(0);}main(){if(fork())SERVER();if(fork())CLIENT();wait(0);wait(0);}五、运行结果消息队列:共享存储区:六、感想及分析此次实验让我对消息队列的获取、传送和共享存储区有了更加深入的了解。理论上来说应该是client和server交替出现,实际上是client先发送了两条,而且最后server接收了2条,但二者分别发送和接收了10条信息,这个和设想是一样的。通过实验我了解到,message的传送和控制并不保证完全同步,当一个程序不再激活状态的时候,它完全可能继续睡眠,造成上面现象,在多次send后才receive。共享存储区的运行结构和预想完全吻合,没有疑问。七、参考资料《2011秋季实验指导》实验五利用信号实现进程间通信一、实验目的学习UNIX类操作系统信号机制,编写Linux环境下利用信号实现进程间通信的方法,掌握注册信号处理程序及signal()调用方法。二、实验内容编写一个程序,完成下列功能:实现一个SIGINT信号的处理程序,注册该信号处理程序,创建一个子进程,父子进程都进入等待。SIGINT信号的处理程序完成的任务包括打印接受到的信号的编号和进程PID。编译并运行该程序,然后在键盘上敲Ctrl+C,观察出现的现象,并解释。三、实验要求按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。四、实验设计创建一个进程,在父子进程中都注册一个用户敲中断键即Ctrl+C的信号处理程序,在子进程中注册一个用户定义信号1,在父进程中注册一个用户定义信号2,然后外部接收信号,最后在main函数中打印出信号的编号和进程PID。在运行时,当用户键入Ctrl+C时,会自动打印出父子进程pid值,但信号的编号始终是父进程中注册的用户定义信号2.代