操作系统实验报告.docx
操作系统实验报告目录:一、实验一41 .实验目的-42 .实验内容43 .实验要求-44 .实验设计45 .实验程序46 .实验结果一一47 .实验感想一一5二、实验二51 .实验目的-52 .实验内容-53 .实验要求-54 .实验设计一-55 .实验程序66 .实验结果87 .实验感想8三、实验三81 .实验目的-82 .实验内容83 .实验要求84 .实验设计95 .实验程序-106 .实验结果117 .实验感想11四、实验四111 .实验目的-112 .实验内容113 .实验要求-114 .实验设计125 .实验结果-166 .实验感想-17五、实验五171 .实验目的-一-172 .实验内容-一-173 .实验要求-174 .实验设计175 .实验程序186 .实验结果197 .实验感想19六、实验六201 .实验目的一一202 .实验内容203 .实验要求-204 .实验设计205 .实验结果236 .实验感想一一24七、实验七241 .实验目的一一242 .实验内容243 .实验要求一一-244 .实验设计一一255 .实验程序276 .实验结果287 .实验感想28实验一UNIX/LINUX入门一、实验目的了解UNIX/LINUX运行环境,熟悉UNlX/LINUX的常用基本命令,熟悉和掌握UNIX/LINUX下C语言程序的编写、编译、调试和运行方法。二、实验内容熟悉UNIX/LINUX的常用基本命令如Is、who、pwd、ps等。练习UNIX/LINUX的文本行编辑器Vi的使用方法熟悉UNIX/LINUX下C语言编译器cc/gcc的使用方法。用Vi编写一个简单的显示-Hello,World!"c语言程序,用gcc编译并观察编译后的结果,然后运行它。三、实验要求按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。四、实验设计1.inux系统常用命令格式:commandoptionargument1argument2.五、实验程序#include<stdio.h>#include<stdlib.h>intmain(void)(printf("HelloWorld!n");system("pause'();return0;1六、实验结果七、实验感想LUbUntUJbUntu:文件(F)编辑(E)查看(V)搜索(三)终端(T)帮助(三)orunacommandasadministrator(user"root"),use"sudo<command>".See"mansudoroot"fordetails.YAubuntUQUbUntu:$Isl.c.c1.JbUnt岬JbUntu:Sgcc-ogcctestl.cjbuntuubuntu:*$Isl.cl.cJbUnt照UbUntU:$./gcctestHelloWorld!ubuntiaubuntuz-S通过第一次室验,熟悉了LlNUX系统的操作,终端的使用,GCC编译C程序实验二进程管理一、实验目的加深对进程概念的理解,明确进程与程序的区别:进一步认识并发执行的实质。二、实验内容(1)进程创建编写一段程序,使用系统调用fork()创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示“a“;子进程分别显示字符“b”和字符“c”。试观察记录屏幕上的显示结果,并分析原因。(2)进程控制修改已编写的程序,将每一个进程输出一个字符改为每一个进程输出一句话,再观察程序执行时屏幕上出现的现象,并分析原因。(3)进程的管道通信编写程序实现进程的管道通信。使用系统调用PiPeo建立一个管道,二个子进程Pl和P2分别向管道各写一句话:Child1issendingamessage!Child2issendingamessage!父进程从管道中读出二个来自子进程的信息并显示(要求先接收Pl,再接收P2)。三、实验要求按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。四、实验设计1、功能设计实验要求建立一个管道实现父进程和子进程间的通信,子进程有两个,子进程向管道里写数据,父进程从管道里读出数据。管道的作用是将两个缓冲区相关连起来,使得一个缓冲区写的东西可以从另一个缓冲区读出来,遵循先进先出的顺序。程序的顺序是这样的:先创建子进程1,向管道写入一句话,子进程1结束后创建子进程2,向管道写入一句话,最后父进程从管道中读出。2、数据结构子进程:使用PiCLtfork。函数创建,返回值为子进程号。管道:使用intpipe(intfiledis)创建无名管道,filedis2为两个文件描述符。3、程序框图五、实验程序#include<stdio.h>#include<string.h>#include<unistd.h>intpipe(intfiledis2);#defineINPUTO#defineOUTPUT1intmain()(intfile-descriptors2;pid_tpidl,pid2;定义子进程charbuf256;intretumed_count;pipe(file_descriptors);创建无名管道if(pidl=fork()=-l)创建子进程1(printf(HErroronforkn,t);exit(l);)if(pid1=0)fprintf("inthespawned(childI)processn");CIoSe(file_descriptOrSuNPUT);关闭通道的读端write(file-descriptorsOUTPUTJ,'childlissendingmessage",strlen("childIissendingmessage");向管道中写一句话exit(O);else(if(pid2=fork()=-l)创建子进程2(printf(MErroronforkn);exit(l);1if(pid2=0)(printf(,inthespawned(child2)processn");close(file_descriptorsINPUT);关闭通道的读端write(file-descriptorsOUTPUT,child2issendingmessage",strlen("child1issendingmessage");向管道中写一句话exit(0);1else(父进程printf(,intheparentprocessn't);CloSe(file_descriptorsOUTPUT);关闭管道的写端returned_count=read(file_descriptorsINPUT,buf,sizeof(buf);printf(',%dbytesofdatareceivedfromspawnedprocess:%sn",returneCLCOUnt,buf);父进程从管道中读出数据)1returnO;六、实验结果心应用程序位置系统力I Oe ubutu(ubunt: l文件(F)编辑(E)查看(V)搜索(S)终端(T)帮助(H)To run a command as See "man sudo root"安装Uubuntuubuntu:$ 2.cUbuntixaubuntu :-$Is22222c: In c:19: c:26: c:33: C:49:function warning: warning: warning: warning:UbUntuIbUntUT2.c gcctest ubuntuubuntu:$画中 ES 12月13日星期二12:56下午 Q ubuntufunction function function function,exit, *exit, *exit, *exit,built-in built-in built-in built-inof of of ofadministrator (user "root"), use "sudo <command>". for details.2.Cgcc -0 gcctest 2.c 'main':incompatible implicit incompatible implicit incompatible implicit incompatible implicit Is gcctest 2.cdeclaration declaration declaration declaration./gcctestin the parent processin the spawned (child2) process25 bytes of data received from spawned process:child2 ubuntuubuntu:-$ in the spawned(childl)processis sending message$7 ubuntu目 UbUntUUbUntu:由图可知,父进程先后接受了子进程向管道写入的两句话,并成功地打印出来。两个子进程分别向管道写入了25个字符,并且是子进程1先写的,子进程2后写的,故输出的顺序也是如此。七、实验感想通过本次实验,我们对进程的概念加深了理解,熟悉了进程的创建方法与作用机制,明确了进程与程序的异同。同时,我们掌握了使用管道通信的机制,进一步认识了并发执行的实质。实验三一个进程启动另一个程序的执行一、实验目的编写Linux环境下,fork。与exec()的结合使用实现一个进程启动另一个程序的执行的基本方法,掌握exec()的几种调用方法。二、实验内容父进程从终端读取要执行的命令,并交给子进程执行。父进程等待子进程结束,并打印子进程的返回值。提示:从终端读取要执行的命令可用fgets()实现。三、实验要求按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。四、实验设计1、功能设计根据实验要求,父进程和子进程将被分配不同的任务:父进程从终端读取要执行的命令交给子进程,然后等待子进程技术打印子进程的返回值;子进程执行父进程读取的命令并返回给父进程。因为子进程执行命令需要打开其他文件,所以需要使用exec()类的函数实现在一个进程来启动另一个程序,在这里应使用exedp()函数从PATH环境变量中查找文件并执行。对于父进程,可以调用fget()从终端读取要执行的命令,以字符串形式存储然后交给子进程执行,待子进程执行完毕后接收子进程返回值并打印。由于要求带参数的命令也可以执行,那么需要在父进程中fets两次,第一次gets得到命令给串command,然后gets参数给串Commandl,并且将这两个参数分别传到子进程的exec()函数,其中前两个都是command,第三个是commandlo2、数据结构用Char*型全局变量command存放指令用Char*型全局变量Commandl存放参数3、程序框图条件?结束五、实验程序#include<stdio.h>charcommand256;charcommandl256J;intmain()(intrtn;子进程的返回数值interrorno;while(l)printf(">);/从终端读取要执行的命令ets(command,256,stdin);printf("<,);从终端读取要执行命令的参数fgets(commandl,256,stdin);commandstrlen(command)-1='0,;command1strlen(command1)-1='0'if(fork()=O)子进程执行此命令errorno=(command10=0)7execlp(command,command,NULL,NULL),execlp(command,command,commandl,NULL);如果没有参数则前者的execlp()函数,如果有参数则执行后者,有无参数只需看COmmandI是否为Operror(command);如果exec函数返回,表明没有正常执行命令,打印错误信息exit(errorno);)else父进程,等待子进程结束,并打印子进程的返回值wait(&rtn);printf(,'childprocessreturn%dn",rtn);)returnO;六、实验结果testZ.ctest.ctextte×tZte×t2.ctext.cchiIdprocessreturn0>rootlocalhostroot#>Is<-a.7.canaconda-ks.cfgZ.bash_historyZ.c.bash-logout3-1.bash-profiIe3-1.c.bashrc3-Z.cshrc3-Z.cdatal.dat4data2.dat4.c.fonts.cache-1?.gconfChildprocessreturn0>root(?IocaIhostrootlit./4.gconfd.gnome.gnome2.gnomeZ_priuate.gnome-desktop.gstreamer.gtkrc.gtkrc-l.Z-gnomeZ.ICEauthorityinsta11.loginstal1.log.syslog.metacity.mozilia.nautiIus.recently-used.tcshrctestZ.ctest.ctextte×tZte×t2.ctext.c.text.c.so.text.c.sup.thumbnails.Trash.viminfo.Xauthority.Xresources由图可知,执行了IS命令,参数为文件按字母顺序显示六、实验感想通过本次实验,我学会了如何用exedp()函数达到一个进程启动另外一个程序的目的。并且对exedp()的几个参数的作用有了一定了解,别且对于fork。和exelp()联合使用的方法和功能。同时,我们进一步熟悉了LINUX系统操作环境,学习了在LlNUX环境下编译和调试程序的技巧。实验四基于消息队列和共享内存的进程间通信2. 一、实验目的3. 1.inux系统的进程通信机构(IPC)允许在任意进程间大批量地交换数据。本实验的目的是了解和熟悉:4. 1.Linux支持的消息通信机制及其使用方法5. 1.inux系统的共享存储区的原理及使用方法。二、实验内容1 .消息的创建、发送和接收使用消息调用msgget()、msgsnd()、msggrev()、msgctrl()编制长度为IK的消息的发送和接收程序。2 .共享存储取得创建、附接和断接使用系统调用shmget()>shmat()ShmCtI()、shmctlO,编制一个与上述功能相同的程序。三、实验要求按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。四、实验设计1、消息的创建、发送和接收(1)功能设计为了实现进程之间消息的创建、发送和接收,首先应定义两个子进程,Server进程负责发送,Client进程负责接收,父进程负责创建。其次需要用到InSgget()、InSgSnd()、msggrev().InSgCtr1()等函数进行对消息的控制。题目要求消息长度为IK,那么msgsnd(id,msgp,size,flag)和msgrcv(id,msgp,size,type,flag)函数中参数size应设为1024,msgget(key,flag)中的key应为75。父进程获得创建消息后,子进程Server先后发送编号为广10的10条消息,子进程CIient先后接收这11条消息,方能达到实验目的。(2)数据结构消息(mymsg):结构体实现,包含的成员变量有消息类型和消息内容,具体实现如下:struct mymsg long int mymsgtype; int text;消息的结构体声明消息类型消息内容;(3)程序框图(4)程序#include<stdio.h>消息结构体消息类型消息内容#include<sys/types.h>#include<unistd.h>#include<sys/ipc.h>#include<sys/msg.h>#include<sys/shm.h>#defineMAX1024structmymsglongintmymsgtype;inttext;msg;main(void)(pid_tPidS,发送进程pid_tPidc;/接收进程intmsgid;消息队列号inti=l;msgid=msgget(KEY,0666|IPC_CREAT);获得一个消息的描述符if(pids=fork()=0)/创建Server子进程while(i<l1)msg.mymsgtype=l1-i;msg.text=i;printf("thesendedmessageis%dthn'i);i+;msgsnd(msgid&msg,MAX,O);向msgid指定的消息队列发送消息,长度为IK)exit(0);)else)i=IO;if(pidc=fork()=0)创建Client子进程while(i!=l)(msgrcv(msgid,&msg,MAX,0,0);从msgid指定的消息队列接收消息printf("themessageis%dthn'msg.text);i=msg.mymsgtype;)exit(0);)else(wait(0);等待子进程结束wait(0);exit(O);)2、共享存储区的创建、附接和断接(1)功能设计为了实现进程通过共享存储区进行通信,需要创建两个进程并且调用ShmgetO.Shmat().ShnlCtI。函数实现共享存储区的创建、附接和断接。由于共享存储区的写入和读取由两个子进程完成,而共享存储区在本程序中为所有进程共用的,因此共享存储区的创建、附接和断接均需要在父进程中完成。具体的实现方式是现在父进程中创建一块共享存储区,然后用int类型指针IiSt指向该存储区的地址;接着创建两个子进程,第一个子进程通过list指针实现向共享存储区写入int类型的数据,第二个子进程通过list指针实现从共享存储区读出int类型的数据。由于两个子进程同时使用了IiSt指针,所以需要控制两个进程互斥,在读进程序中添加了SIeeP(D语句。(2)数据结构通过Shmid=Shmget(key,size,flag)函数建立(获得)共享存储区,返回该共享存储区的描述符shmido(3)程序框图(4)程序#include<stdio.h>#include<stdlib.h>#include<string.h>#include<unistd.h>#include<sys/types.h>#include<sys/ipc.h>#include<sys/shm.h>#defineMAX11#defineKEY75main()inti,childI,child2,running=1;定义子进程号intid;共享存储区描述符int*list;id=shmget(KEY,sizeof(int)*MAX,IPCLCREATIo666);建立一块共享存储区,返回该共享存储区的描述符idHst=(int*)shmat(idAO);将list指针指向共享存储区if(child1=fbrk()=-l)printf(,errorinforkan");exit(l);)if(childl=O)/创建子进程childlSleeP(1);暂停一段时间,等待第一个子进程结束fr(i=0;i<=10;i+)rintf(,yourmessageis:%dn"Jisti);从缓冲区里读出数据exit(0);)elseif(child2=fbrk()=-1)(printf("errorinforkan");exit(l);)if(child2=0)创建子进程child2i=0;while(l)IiSti=i;向缓冲区里写入数据printf("themessagesentis:%dn,listi);if(listi=10)break;i+;lexit(0);)elsewait(0);wait(0);Shmdt(Iist);将共享存储区与进城断开ShmctKidJPC-RMID,0);/将共享存储区标志为被销毁的exit(0);)五、实验结果(1)消息的创建、发送和接收fUbUntUUbUntu:文件(F)编辑(E)查看(V)搜索(S)终端(T)帮助(H)UbuntuQubuntu:*$ IS gcctest 4.1.c4.1.c gcctestUbUntUubuntu:一$ ./gcctestthe sendedmessage is 1 ththe sendedmessage is 2 ththe sendedmessage is 3 ththe sendedmessage is 4 ththe sendedmessage is 5 ththe sendedmessage is 6 ththe sendedmessage is 7 ththe sendedmessage is 8 ththe sendedmessage is 9 ththe sendedmessage is l ththe the the the the the the the the themessage message message message message message message message message messageis is is is is is is is is is123456789th th th th th th th th thl thubuntuubuntu:*$第一个子进程一次发了10条消息,第二个子进程一次接收了10条消息,消息队列先进先出(2)共享存储区的创建、附接和断接Q介UbUntUJbUntU:文件(F)编辑(E)查看(V)搜索终端(T)帮助(H)ubuntu(aubuntu :-$the the the the the the the the the the themessage message message message message message message message message message messageyour messagesent sent sent sent sent sent sent sent sent sent sent is:./gcctest is : IS : 10is: is: is: is: is: is: is: is: is: is: l:$yourmessageyourmessageyourmessageyourmessageyourmessageyourmessageyourmessageyourmessageyourmessageyourmessageubuntu<ubuntu第一个子进程向共享存储区写入了11个数据,第二个子进程从共享存储区读取,两个进程之间是互斥执行的。六、实验感想通过本次实验,我学会了如何用消息队列和共享内存的方式实现进程间的通信,掌握了Linux系统的消息通信机制和共享存储区的原理,并在实践过程中掌握了它们的使用方法。在编程和调试的过程中,我进一步熟悉了LINUX环境下的编译过程和调试方法。实验五利用信号实现进程间通信一、实验目的学习UNIX类操作系统信号机制,编写LinUX环境下利用信号实现进程间通信的方法,掌握注册信号处理程序及Signalo调用方法。二、实验内容编写一个程序,完成下列功能:实现一个SlGlNT信号的处理程序,注册该信号处理程序,创建一个子进程,父子进程都进入等待。SIGINT信号的处理程序完成的任务包括打印接受到的信号的编号和进程PIE编译并运行该程序,然后在键盘上敲Ctrl+C,观察出现的现象,并解释。提示:参见“五、补充材料”中的SignaIo的基本用法。三、实验要求按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。四、实验设计1、功能设计本实验要求利用信号实现进程间通信。为了实现实验目的,需要实现一个SIGINT信号的处理函数func()并注册该信号处理函数。信号处理函数需要完成的任务应包括打印接受到的信号的编号和进程的PID,所以func()函数应能实现打印当前进程的pid以及根据接收到的信号的编号打印出该信号名称的功能。父进程和子进程分别接收两个不同的信号,因此两个进程调用Signai()函数时应为不同的信号注册信号处理函数。本次实验采用了SIGINT和SlGUSRl两个信号。为了让父子进程都能够接收到信号,在注册信号处理函数后应让两个进程进入等待,并且为了方便验证试验结果,让父进程接收SIGlNT信号,子进程接收SlGUSRl信号。2、数据结构信号(SIGNAL):UNIX系统含有20种信号。可以使用SignaIo函数为每个信号注册信号处理函数。3、程序框图五、实验程序#include<stdio.h>#include<signal.h>#include<unistd.h>voidfunc(inti);intpid;main()(if(pid=fork()=0)创建子进程(printf(,sonpidz%dn",pid);/打印子进程号Signal(SIGUSRhfunc);/注册SlGUSRl的信号处理程序for(;)子进程进入等待pause();1else(printf("fatherpid%dn",pid)/打印父进程号SignaI(SIGINTfunc);注册SlGINT的信号处理程序for(;)父进程进入等待pause();)voidfunc(inti)/信号处理函数printf("pid%dn,pid);if(i=SIGUSR1)printf(',receivedSIGUSRln,');elseif(i=SIGUSR2)printf(,receivedSIGUSR2n");elseif(i=SIGINT)(printf(,receivedSIGINT%dn",i);exit(l);)exit(O);)六、实验结果,-UbUntU©ubuntu:文件(F)编辑(E)查看(V)搜索(三)终端(T)帮助(三)UbUntUiIbUntU:$UbUntUJbUntU:$IJbUntU©ubuntu:$UbUntiJiJbUntU:$IJbUntUiIbUntlJ:$Iibuntutaubuntu:$Is5.c5.cUbUntUJbUntli: $ < 5.c: In function 5.c:63: warning: 5.c:67: warning: UbUntUiJbUntli: fatherpid:4904 sonpid pcpid:4904 received SIGINT 2gcc5.c-O5*func*:incompatibleimplicitdeclarationofbuilt-infunction,exit,incompatibleimplicitdeclarationofbuilt-infunction,exit,./5UbUntUiJbUntU:$./5&2495UbUntUiJbUntUfatherpid:4906sonpidzkill-USRl496UbUntUiJbUntli:$pid:6receivedSIGUSR1如图所示,第一次执行后按CtrI+c后,父进程接收信号,信号处理程序输出父进程号4094和信号名称。第二次使用./5&后台运行此程序,使用kill-USRl4096时,子进程接收信号,信号处理程序输出子进程号0,并输出信号名称。七、实验心得通过本次实验,我掌握了注册信号处理程序及SignaI()调用方法,并且了解了如何让程序在后台运行的方法。我也进一步了解了LINUX系统中进程同步与通信的原理。实验六线程的创建一、实验目的编写Linux环境下的多线程程序,了解多线程的程序设计方法,掌握最常用的三个函pthread-create,pthreadjoin和PthreacLeXit的用法。二、实验内容1、主程序创建两个线程myThreadl和myThread2,每个线程打印一句话。使用PthreaeLCreate(&id,NULL,(void*)thread,NULL)完成。提示:先定义每个线程的执行体,然后在main中()创建几个线程,最后主线程等待子线程结束后再退出。2、创建两个线程,分别向线程传递如下两种类型的参数传递整型值传递字符三、实验要求按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。四、实验设计1、创建两个进程每个进程打印一句话(1)功能设计题目要求创建两个线程,每个线程打印一句话,可以认为两个线程的功能是相同的,故只需要写一个线程的运行函数thread。,在这个函数里有一个Printf输出一句话即可。然后在main函数里分别创建两个线程,然后等待两个线程结束。(2)数据结构线程:使用PthreaCLCreate()创建。每个线程有相应的线程标示符,也有各自的属性。线程可以和线程运行函数绑定,并可以在创建线程时确定该线程运行函数的参数。(3)程序框图#include<stdio.h>#include<pthread.h>voidthread(void)/线程运行函数printf("ThisisaPthread.n");输出一句话)intmain(void)(pthread_tidl,id2;定义两个线程标识符inti,ret;ret=pthread_create(&id1,NULL,(void*)thread,NULL);创建线程标识为idlif(ret!=O)/线程创建失败printf("Createpthreaderror!n");exit(1);)ret=pthread_create(&id2,NULL,(void)thread,NULL);仓IJ建线程标识为id2if(ret!=O)线程创建失败printf("Createpthreaderror!n");exit(1);)printf("Thisisthemainprocess.n");pthreadjoin(id1,NULL);/等待第一个线程结束pthreadJoin(id2,NULL);等待第二个线程结束return(0);2、创建两个进程每个进程打印一句话分别向线程传递如下两种类型的参数:整型值、字符(1)功能设计题目要求创建两个线程,两个线程分别传递int型和Char型数据给线程运行函数。所以要编写两个不同的线程运行函数分别接收int型和char型的数据。相应的pthread,create()函数中要给第四个参数,作为形参传进线程运行函数。(2)数据结构线程:同1,使用PthreaCLCreate()创建。每个线程有相应的线程标示符,也有各自的属性。线程可以和线程运行函数绑定,并可以在创建线程时确定该线程运行函数的参数。(3)程序框图开始定义线程标创建线程1并与threadchar(char*c)函数绑定创建线程2并与threadint(int*n)函数绑定(4)程序#include<pthread.h>#include<stdio.h>#include<stdlib.h>#include<unistd.h>voidthreadchar(char*c)接收字符的线程运行函数(printf("receiveachan%cn,c);)voidthreadint(int*i)接收整数的线程运行函数(printf("receiveaint:%dn",i);)intmain(void)(pthread_tidl,id2;/定义两个线程标识符intret;charc='t'char*a=c;定义Char*指针变量传参数用ret=pthread_create(&id1,NULL,(void*)threadchar,a);创建线程1,第四个参数为Char*型变量用来传递字符if(ret!=O)/线程创建失败printf("Createpthreaderror!n");exit(1);)inti=99;int