北京工业大学操作系统实验报告0122
操作系统实验报告
专 业 计算机科学与技术 年 级 本科三年级 学 号 ******** 姓 名 樊文舟
第 1 页 共 22 页
12070131 樊文舟
目录:
一、实验一 ---------------------------------------------3
1.实验目的-----------------------------------------------------------3 2.实验内容-----------------------------------------------------------3 3.实验要求-----------------------------------------------------------3 4.实验设计-----------------------------------------------------------3 5.实验程序-----------------------------------------------------------3 6.实验结果-----------------------------------------------------------4 7.实验感想-----------------------------------------------------------4 1.实验目的-----------------------------------------------------------5 2.实验内容-----------------------------------------------------------5 3.实验要求-----------------------------------------------------------5 4.实验设计-----------------------------------------------------------5 5.实验程序-----------------------------------------------------------6 6.实验结果-----------------------------------------------------------7 7.实验感想-----------------------------------------------------------7 1.实验目的-----------------------------------------------------------8 2.实验内容-----------------------------------------------------------8 3.实验要求-----------------------------------------------------------8 4.实验设计-----------------------------------------------------------9 5.实验程序-----------------------------------------------------------10 6.实验结果-----------------------------------------------------------11 7.实验感想-----------------------------------------------------------11 1.实验目的-----------------------------------------------------------12 2.实验内容-----------------------------------------------------------12 3.实验要求-----------------------------------------------------------12 4.实验设计-----------------------------------------------------------12 5.实验结果-----------------------------------------------------------12 6.实验感想-----------------------------------------------------------12
二、实验二 ---------------------------------------------4
三、实验三 ---------------------------------------------8
四、实验四 ---------------------------------------------12
个人总结
---------------------------------------------12
第 2 页 共 22 页
12070131 樊文舟
实验一 UNIX/LINUX入门
一、 实验目的
了解UNIX/LINUX运行环境,熟悉UNIX/LINUX的常用基本命令,熟悉和掌握UNIX/LINUX下C语言程序的编写、编译、调试和运行方法。
二、 实验内容
1、熟悉UNIX/LINUX的常用基本命令如ls、who、pwd、ps等。(常用Linux命令在附录中列出,请参阅。) 2、熟悉UNIX/LINUX下C语言编译器cc/gcc的使用方法。编写一个简单的显示“Hello,World!”C语言程序,用gcc编译并观察编译后的结果,然后运行它。 具体方法如下:
(1)开机选择Linux操作系统进入,根据要求输入用户名root,密码rootroot。 (2)尝试使用实验指导书中提供的各种指令。步骤如下:
如果你机器是英文系统,找ApplicationsAccessories Terminal,并运行。 如果你机器是中文系统,找 应用附件终端,并运行。 注意:Terminal是一个命令行系统,尝试运行相关的命令。 (3)尝试写一个Hello world程序。步骤如下: a) 选择一个目录下创建一个文件example.c
b) 双击代表example.c的图标进入编辑器并输入hello world代码 c) 保存并退出
d) 在终端(Terminal)中对example.c进行编译。编译命令为:
gcc example.c –o example
e) 运行编译好的程序。指令为:
./example
三、 实验要求
按照要求编写程序,放在相应的目录中,编译成功后执行。
四、 实验设计
Linux 系统常用命令格式:
command [option] [argument1] [argument2] ...
五、 实验程序
#include printf (\"Hello World!\\n\"); system (\"pause\"); return 0; } 第 3 页 共 22 页 12070131 樊文舟 六、 实验结果 七、 实验感想 通过第一次室验,熟悉了LINUX系统的操作,终端的使用,GCC编译c程序 实验二 进程管理 一、实验目的 加深对进程概念的理解,明确进程与程序的区别;进一步认识并发执行的实质。 二、实验内容 (1)进程创建 编写一段程序,使用系统调用fork()创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示“a“;子进程分别显示字符”b“和字符“c”。试观察记录屏幕上的显示结果,并分析原因。(提示:对每个进程的打印循环执行10次,则可以发现执行顺序的不同) (2)进程控制 修改已编写的程序,将每一个进程输出一个字符改为用一个循环输出1000个字符(父进程输出1000个“a”,子进程分别输出1000个“b”和“c”),再观察程序执行时屏幕上出现的现象,并分析原因。 (3)进程的管道通信 编写程序实现进程的管道通信。使用系统调用pipe()建立一个无名管道,二个子进程P1和P2分别向管道各写一句话: 第 4 页 共 22 页 12070131 樊文舟 Child 1 is sending a message! Child 2 is sending a message! 父进程从管道中读出二个来自子进程的信息并显示(要求先接收P1的消息,再接收P2的消息)。 三、实验要求 按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。 四、实验设计 1、功能设计 实验要求建立一个管道实现父进程和子进程间的通信,子进程有两个,子进程向管道里写数据,父进程从管道里读出数据。管道的作用是将两个缓冲区相关连起来,使得一个缓冲区写的东西可以从另一个缓冲区读出来,遵循先进先出的顺序。 程序的顺序是这样的:先创建子进程1,向管道写入一句话,子进程1结束后创建子进程2,向管道写入一句话,最后父进程从管道中读出。 2、数据结构 子进程:使用pid_t fork()函数创建,返回值为子进程号。 管道:使用int pipe(int filedis[2])创建无名管道,filedis[2]为两个文件描述符。 3、程序框图 子进程1开始 开始 向管道中写入定义子进程号 数据 和文字描述符 子进程1结束 创建子进程1 子进程2开始 创建子进程2 向管道中写入 数据 父进程接收管道 中数据 子进程2结束 结束 第 5 页 共 22 页 12070131 樊文舟 五、实验程序 #include int pipe(int filedis[2]); #define INPUT 0 #define OUTPUT 1 int main() { int file_descriptors[2]; pid_t pid1,pid2; //定义子进程 char buf[256]; int returned_count; pipe(file_descriptors);//创建无名管道 if((pid1=fork())==-1) //创建子进程1 { printf(\"Error on fork\\n\"); exit(1); } if(pid1==0) { printf(\"in the spawned(child1)process\\n\"); close(file_descriptors[INPUT]); //关闭通道的读端 write(file_descriptors[OUTPUT],\"child1 is sending message\sending message\"));//向管道中写一句话 exit(0); } else{ if((pid2=fork())==-1) //创建子进程2 { printf(\"Error on fork\\n\"); exit(1); } if(pid2==0) { printf(\"in the spawned(child2)process\\n\"); close(file_descriptors[INPUT]); //关闭通道的读端 write(file_descriptors[OUTPUT],\"child2 is sending message\sending message\"));//向管道中写一句话 第 6 页 共 22 页 12070131 樊文舟 exit(0); } else{ //父进程 printf(\"in the parent process\\n\"); close(file_descriptors[OUTPUT]); //关闭管道的写端 returned_count=read(file_descriptors[INPUT],buf,sizeof(buf)); printf(\"%d bytes of data received from spawned process:%s \\n\父进程从管道中读出数据 } } return 0; } 六、实验结果 由图可知,父进程先后接受了子进程向管道写入的两句话,并成功地打印出来。 两个子进程分别向管道写入了25个字符,并且是子进程1先写的,子进程2后写的,故输出的顺序也是如此。 七、实验感想 通过本次实验,我们对进程的概念加深了理解,熟悉了进程的创建方法与作用机制,明确了进程与程序的异同。同时,我们掌握了使用管道通信的机制,进一步认识了并发执行的实质。 第 7 页 共 22 页 12070131 樊文舟 实验三 线程的管理 一、实验目的 编写Linux环境下的多线程程序,了解多线程的程序设计方法,掌握最常用的三个函数pthread_create,pthread_join和pthread_exit的用法 二、实验内容 1、 主程序创建两个线程myThread1和myThread2,每个线程打印一句话。使用 pthread_create(&id,NULL,(void *) thread,NULL)完成。 提示: 先定义每个线程的执行体,然后在main中()创建几个线程,最后主线程等待子线程结束后再退出。 2、创建两个线程,分别向线程传递如下两种类型的参数 传递整型值 传递字符 三、实验要求 按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。 四、实验设计 1、创建两个进程每个进程打印一句话 (1)功能设计 题目要求创建两个线程,每个线程打印一句话,可以认为两个线程的功能是相同的,故只需要写一个线程的运行函数thread(),在这个函数里有一个printf输出一句话即可。然后在main函数里分别创建两个线程,然后等待两个线程结束。 (2)数据结构 线程:使用pthread_create()创建。每个线程有相应的线程标示符,也有各自的属性。线程可以和线程运行函数绑定,并可以在创建线程时确定该线程运行函数的参数。 (3)程序框图 创建线程2并与thread() 开始 函数绑定 定义线程标 识符 创建线程1并与thread() 函数绑定 ( 第 8 页 共 22 页 等待线程结束 结束 12070131 樊文舟 4)程序 #include void thread(void) //线程运行函数 { printf(\"This is a pthread.\\n\"); //输出一句话 } int main(void) { pthread_t id1,id2; //定义两个线程标识符 int i,ret; ret=pthread_create(&id1,NULL,(void *) thread,NULL);//创建线程标识为id1 if(ret!=0){ //线程创建失败 printf (\"Create pthread error!\\n\"); exit (1); } ret=pthread_create(&id2,NULL,(void *) thread,NULL); //创建线程标识为id2 if(ret!=0){ //线程创建失败 printf (\"Create pthread error!\\n\"); exit (1); } printf(\"This is the main process.\\n\"); pthread_join(id1,NULL); //等待第一个线程结束 pthread_join(id2,NULL); //等待第二个线程结束 return (0); } 2、创建两个进程每个进程打印一句话分别向线程传递如下两种类型的参数 :整型值、字符 (1)功能设计 题目要求创建两个线程,两个线程分别传递int型和char型数据给线程运行函数。所以要编写两个不同的线程运行函数分别接收int型和char型的数据。相应的pthread_create()函数中要给第四个参数,作为形参传进线程运行函数。 (2)数据结构 线程:同1,使用pthread_create()创建。每个线程有相应的线程标示符,也有各自的属性。线程可以和线程运行函数绑定,并可以在创建线程时确定该线程运行函数的参数。 第 9 页 共 22 页 12070131 樊文舟 (3)程序框图 开始 定义线程标 识符 创建线程1并与threadchar(char* c) 函数绑定 创建线程2并与threadint(int *n) 函数绑定 等待线程结束 结束 (4)程序 #include void threadchar(char * c) //接收字符的线程运行函数 { printf(\"receive a char:%c\\n\} void threadint(int * i) //接收整数的线程运行函数 { printf(\"receive a int:%d\\n\} int main(void) { pthread_t id1,id2; //定义两个线程标识符 int ret; char c='t'; 第 10 页 共 22 页 12070131 樊文舟 char *a=c; //定义char*指针变量传参数用 ret=pthread_create(&id1,NULL,(void *) threadchar,a); //创建线程1,第四个参数为char*型变量用来传递字符 if(ret!=0){ //线程创建失败 printf (\"Create pthread error!\\n\"); exit (1); } int i=99; int *b=i; //定义int*指针变量传参数用 ret=pthread_create(&id2,NULL,(void *) threadint,b); //创建线程2,第四个参数为int*型变量用来传递字符 if(ret!=0){ //线程创建失败 printf (\"Create pthread error!\\n\"); exit (1); } printf(\"This is the main process.\\n\"); pthread_join(id1,NULL); //等待线程1结束 pthread_join(id2,NULL); //等待线程2结束 return (0); } 五、实验结果 由图可知两个线程主程序创建了两个进程这两个进程分别输出了一句话 第 11 页 共 22 页 12070131 樊文舟 主程序分别创建了两个线程并向线程1传递了‘t’向线程2传递了99,线程运行函数分别输出告知接收了这两个参数。 六、实验感想 通过本次实验,我学会了如何使用LINUX下的线程创建函数pthread_create()来创建线程,并且向线程传递参数。同时更加熟练的使用LINUX。 实验四 利用信号量实现进程控制 一、实验目的 学习UNIX类(System V)操作系统信号量机制,编写Linux环境下利用信号量实现进程控制的方法,掌握相关系统调用的使用方法。 二、实验内容 创建4个线程,其中两个线程负责从文件读取数据到公共的缓冲区,另两个线程从缓冲区读取数据作不同的处理(加和乘运算)。使用信号量控制这些线程的执行。 提示: (1)参见“四、补充材料”中的相关系统调用的基本用法。 (2)创建4个线程,其中2个线程用于从文件中读数据到缓冲区中(例如:一个进程读1.dat文件,另一个进程读2.dat文件),另2个线程从缓冲区中取数据作处理。 事先编辑好数据文件如:1.dat和2.dat,假设它们的内容分别为1 2 3 4 5 6 7 8 9 10和 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 ,然后运行你编写的程序,应得到如下类似的结果:Multiply:-1*-2=2 Plus:-1+-2=-3 第 12 页 共 22 页 12070131 樊文舟 Multiply:9*10=90 Plus:-9+-10=-19 Multiply:-7*-8=56 Plus:-5+-6=-11 Multiply:-3*-4=12 Plus:9+10=19 Plus:7+8=15 Plus:5+6=11 三、实验要求 按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。 四、实验设计 1、功能设计 题目要求创建4个线程,其中两个负责从文件读数据到缓冲区,另两个负责从缓冲区读数据进行加和乘的运算。我对这4个线程进行如下安排,线程1读后线程2才可以读,线程2读了后线程3才可以进行加的运算,线程3加完了后线程4才能进行乘的运算,线程4乘完后线程1才能继续读。故需4个信号量sem1,sem2,sem3,sem4。线程1消费sem1生产sem2,线程2消费sem2生产sem3,线程3消费sem3生产sem4,线程4消费sem4生产sem1,形成一个循环,直到文件结束为止。 2、数据结构 信号量(semaphore):数据类型为结构 sem_t,本质上是一个长整型的数。一共4个 公共缓冲区(stack):采用2维数组的方式实现(stack[NUM][2])。数组中的两列分别存储两个文件中的数据。该2维数组还有一个索引:size,指向2维数组的顶部。读线程每次从文件读出两个数放到stack[NUM][0]和stack[NUM][1] 线程A开始 3、程序框图 开始 到文件尾? 定义线程标识符,缓冲区 Y 和信号量 初始化信号量 P(sem1) N 从文件读出两个数创建4个线程并分别与 相应函数绑定 第 13 页 共 22 页 据到缓冲区 12070131 樊文舟 线程B开始 等待线程结束 P(sem2) Y 结束 线程A结束 到文件尾? N P(sem2) P(sem3) 结束 线程B结束 线程D开始 从文件读出两个数据到缓冲区 线程C开始 到文件尾? N 到文件尾? P(sem4) N 从缓冲区取两个P(sem3) 数相乘 从缓冲区取两个 P(sem1) 数相加 线程D结束 P(sem4) 第 14 页 共 22 页 12070131 樊文舟 线程C结束 五、实验程序 #include sem_t sem,sem1; void ReadData1(void){ ) FILE *fp=fopen(\"1.dat\从文件中读数据 sem_wait(&sem1); int i; for(i=0;i<10;i++) fscanf(fp,\"%d\ sem_post(&sem1); sem_post(&sem); fclose(fp); } void ReadData2(void){ FILE *fp=fopen(\"2.dat\ sem_wait(&sem1); int i; for(i=0;i<10;i++) 线程C结束 fscanf(fp,\"%d\ sem_post(&sem1); sem_post(&sem); fclose(fp); } void HandleData1(void){ int i; sem_wait(&sem); //等,读完了加到1才能处理 for(i=0;i<5;i++){ int m=stack[b++]; int n=stack[b++]; printf(\"Plus:%d+%d=%d\\n\ } } 第 15 页 共 22 页 线程D结束 12070131 樊文舟 void HandleData2(void){ int i; sem_wait(&sem); for(i=0;i<5;i++){ int m=stack[b++]; int n=stack[b++]; printf(\"Multiply:%d*%d=%d\\n\ } } int main(void) { pthread_t t1,t2,t3,t4; sem_init(&sem,0,0);//初始化一个信号量为0,同步 sem_init(&sem1,0,1); //初始化为1,互斥 pthread_create(&t1,NULL,(void *)HandleData1,NULL); pthread_create(&t2,NULL,(void *)HandleData2,NULL); pthread_create(&t3,NULL,(void *)ReadData1,NULL); pthread_create(&t4,NULL,(void *)ReadData2,NULL); pthread_join(t1,NULL); pthread_join(t2,NULL); pthread_join(t3,NULL); pthread_join(t4,NULL); } 六、实验感想 通过本次实验,我进一步掌握了如何使用LINUX下的线程创建函数pthread_create()创建线程,并且学会了如何使用信号量控制进程的运行,学会了使用消费函数 sem_wait(),生产函数sem_post(),以及如何初始化信号量,同时也掌握了文件的读取 方法,本次实验加深了我对信号量的认识。 实验五 基于消息队列和共享内存的进程间通信 一、实验目的 Linux系统的进程通信机构(IPC)允许在任意进程间大批量地交换数据。本实验的目的是了解和熟悉: 1. Linux支持的消息通信机制及其使用方法 2. Linux系统的共享存储区的原理及使用方法。 二、实验内容 1. 消息的创建、发送和接收 使用消息调用msgget()、msgsnd()、msgrcv()、msgctl()编制长度为1K的消息的发送和接收程序。 第 16 页 共 22 页 12070131 樊文舟 2. 共享存储取得创建、附接和断接 使用系统调用shmget()、shmat()、shmctl(),编制一个与上述功能相同的程序。 三、实验要求 按照要求编写程序,放在相应的目录中,编译成功后执行,并按照要求分析执行结果,并写出实验报告。 四、实验设计 1、消息的创建、发送和接收 (1)功能设计 为了实现进程之间消息的创建、发送和接收,首先应定义两个子进程,Server进程负责发送,Client进程负责接收,父进程负责创建。其次需要用到msgget()、msgsnd()、msggrev()、msgctrl()等函数进行对消息的控制。题目要求消息长度为1K,那么msgsnd(id,msgp,size, flag)和msgrcv(id,msgp,size,type,flag)函数中参数size应设为1024,msgget(key,flag)中的key应为75。父进程获得创建消息后,子进程Server先后发送编号为1~10的10条消息,子进程Client先后接收这11条消息,方能达到实验目的。 (2)数据结构 消息(mymsg):结构体实现,包含的成员变量有消息类型和消息内容,具体实现如下: struct mymsg{ //消息的结构体声明 long int mymsgtype; //消息类型 int text; //消息内容}; (3)程序框图 开始 子进程 Server开始 定义子进程 号 向消息队列 中发送10条 获得一个消 息的描述符 子进程Server 结束 创建Server 子进程 子进程 Client开始 创建Client子 进程 向消息队列 中发送10条 结束 第 17 页 共 22 页 12070131 樊文舟 子进程Client 结束 #include struct mymsg{ //消息结构体 long int mymsgtype; //消息类型 int text; //消息内容 }msg; main(void) { pid_t pids;//发送进程 pid_t pidc;//接收进程 int msgid; //消息队列号 int i=1; msgid=msgget(KEY,0666|IPC_CREAT);//获得一个消息的描述符 if((pids=fork())==0){ //创建Server子进程 while(i<11){ msg.mymsgtype=11-i; msg.text=i; printf(\"the sended message is %d th\\n\i++; msgsnd(msgid,&msg,MAX,0); //向msgid指定的消息队列发送消息,长度为1K } exit(0); } else{ i=10; if((pidc=fork())==0){ //创建Client子进程 while(i!=1){ msgrcv(msgid,&msg,MAX,0,0); //从msgid指定的消息队列接收消息 printf(\"the message is %d th\\n\i=msg.mymsgtype; } exit(0); } 第 18 页 共 22 页 12070131 樊文舟 else{ wait(0); //等待子进程结束 wait(0); exit(0);}}} 2、共享存储区的创建、附接和断接 (1)功能设计 为了实现进程通过共享存储区进行通信,需要创建两个进程并且调用shmget()、shmat()、shmctl()函数实现共享存储区的创建、附接和断接。由于共享存储区的写入和读取由两个子进程完成,而共享存储区在本程序中为所有进程共用的,因此共享存储区的创建、附接和断接均需要在父进程中完成。具体的实现方式是现在父进程中创建一块共享存储区,然后用int类型指针list指向该存储区的地址;接着创建两个子进程,第一个子进程通过list指针实现向共享存储区写入int类型的数据,第二个子进程通过list指针实现从共享存储区读出int类型的数据。由于两个子进程同时使用了list指针,所以需要控制两个进程互斥,在读进程序中添加了sleep(1)语句。 (2)数据结构 通过shmid=shmget (key ,size ,flag)函数建立(获得)共享存储区,返回该共享存储区的描述符shmid。 (3)程序框图 子进程1开始 开始 向共享存储区中定义子进程 读出数据 号 建立共享存储区并连接 子进程2开始 创建子进程1 子进程2 子进程1结束 等待子进程结束 向共享存储区中写入数据 断开共享存储区 子进程2结束 结束 第 19 页 共 22 页 12070131 樊文舟 (4)程序 #include {int i,child1,child2,running=1;//定义子进程号 int id; //共享存储区描述符 int *list; id=shmget(KEY,sizeof(int)*MAX,IPC_CREAT|0666); //建立一块共享存储区,返回该共享存储区的描述符id list=(int*)shmat(id,0,0); //将list指针指向共享存储区 if((child1=fork())==-1){ printf(\"error in fork a\\n\"); exit(1);} if(child1==0){ //创建子进程child1 sleep(1); //暂停一段时间,等待第一个子进程结束 for(i=0;i<=10;i++) printf(\"your message is: %d \\n\从缓冲区里读出数据 exit(0); }else{ if((child2=fork())==-1){ printf(\"error in fork a\\n\"); exit(1);} if(child2==0){ //创建子进程child2 i=0; while(1){ list[i]=i; //向缓冲区里写入数据 printf(\"the message sent is : %d\\n\if(list[i]==10) break; i++;} exit(0);} 第 20 页 共 22 页 12070131 樊文舟 else {wait(0); wait(0); shmdt(list); //将共享存储区与进城断开 shmctl(id,IPC_RMID,0);// 将共享存储区标志为被销毁的 exit(0);}}} 五、实验结果 (1)消息的创建、发送和接收 第一个子进程一次发了10条消息,第二个子进程一次接收了10条消息,消息队列先进先出 (2)共享存储区的创建、附接和断接 第 21 页 共 22 页 12070131 樊文舟 第一个子进程向共享存储区写入了11个数据,第二个子进程从共享存储区读取,两个进程之间是互斥执行的。 六、实验感想 通过本次实验,我学会了如何用消息队列和共享内存的方式实现进程间的通信,掌握了Linux系统的消息通信机制和共享存储区的原理,并在实践过程中掌握了它们的使用方法。在编程和调试的过程中,我进一步熟悉了LINUX环境下的编译过程和调试方法。 个人总结 通过本实验真正使用到了Linux系统,对linux系统有个大概的了解,知道了linux系统的大体结构和使用方法。知道了各个组合键的意义,使我更加了解Linux一些常用指令的操作以及其作用,对于一个刚开始接触lniux操作系统的初学者来说非常有用,助于以后能够更进一步学习Linux操作系统。 第 22 页 共 22 页 因篇幅问题不能全部显示,请点此查看更多更全内容