操作系统课程设计说明书 基于Linux的进程之间通信_第1页
操作系统课程设计说明书 基于Linux的进程之间通信_第2页
操作系统课程设计说明书 基于Linux的进程之间通信_第3页
操作系统课程设计说明书 基于Linux的进程之间通信_第4页
操作系统课程设计说明书 基于Linux的进程之间通信_第5页
已阅读5页,还剩15页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、中北大学操作系统课程设计说 明 书 学 院、系:软件学院专 业:软件工程学 生 姓 名:学 号:设 计 题 目:基于Linux的进程之间通信 实现信号量通信机制(哲学家进餐) 起 迄 日 期:2015年12月28日- 2016年1月8日指 导 教 师:何志英   2015 年12月25日1 需求分析1.1小组的拿到的任务是:设计内容:(1)实现管道通信,要求见P183习题(3)。(2)实现信号量通信机制,要求见P191习题(3)。(3)实现消息缓冲通信机制,要求见P197习题。(4)实现共享内存区通信机制,要求见P201习题(2)。要求:(1)用Linu

2、x中进程控制系统调用函数来创建进程(线程)。(2)输出进程通信时同步的说明信息。1.2小组分工我拿到的题目是:(2)实现信号量通信机制,要求见P191习题(3)。1.3题目的要求如下:1.3.1.哲学家进餐问题描述:设有5个哲学家,共享一张放有5把椅子和5把叉子的圆桌,每人分得一把椅子。哲学家们在肚子饥饿时才试图分两次从两边捡起两把叉子就餐。条件:1.每个人只有拿到两把叉子时,哲学家才能吃饭2.如果叉子已在他人手上,则哲学家必须等到他人吃完后才能拿起叉子3.任性的哲学家在自己未拿到两把叉子吃饭之前,绝不放下自己手中的叉子1.3.2问题:1.什么情况下5个哲学家全部都吃不上饭?答:当5个哲学家每

3、人手中都拿到了1把叉子(共5把),即不肯放下自己手中的叉子又想要得到左右邻居的叉子时,每个哲学家永远拿不到两把叉子,所有哲学家都在等待另一把叉子,就会导致这5个哲学家谁都吃不上饭。也就是产生死锁后的情况。2.编程实现没有人饿死(永远拿不到两个叉子)的算法。答:程序请看代码实现。分析:没有人饿死,就是不允许出现死锁的情况(5个哲学家每人1把叉子)1.3.3解决死锁的方法有三种:1.至多允许四位哲学家同时去拿左边的叉子,最终保证至少有一位哲学家能够进餐,并且在用毕时能释放出他用过的两只叉子,从而使更多哲学家能够进餐;2.规定当哲学家的左右两只叉子均可用时,才允许他拿起叉子进餐;3.规定奇数号的哲学

4、家先拿他左边的叉子,然后再去拿他右边的叉子,而偶数号哲学家则相反。五位哲学家都先竞争奇数号叉子,获得后再竞争偶数号叉子,最终总有一位哲学家会因为获得两只叉子而进餐。1.3.4我采用的解决死锁问题的方法我采用的解决死锁的方法是第二种,即在哲学家拿起叉子前先判断他左右邻居的情况,只要左右邻居中有一位正在进餐(叉子已经被邻居拿到,邻居进餐结束前自己无法获得其叉子),就不允许其拿起叉子进餐,这就可以预防死锁的情况发生。1.4软件需要完成的功能:按照题目要求,需要调用Linux操作系统函数使用信号量机制完成对哲学家进餐问题的求解,要求所有哲学家都能吃到食物,并且要防止哲学家在竞争叉子过程发生死锁。程序应

5、该包含如下功能:1.哲学家思考功能:哲学家在进餐前和进餐后处于思考状态;2.哲学家拿起叉子动能:哲学家进餐前需要拿起叉子,在这个过程中可能发生死锁,所以要在这个功能中编写防止死锁的方法;3.哲学家进餐功能:哲学家拿起叉子后开始进餐;4.哲学家放下叉子功能:哲学家用餐完毕,放下叉子,并通知其左右邻居;5.执行P、V操作功能:由于要使用信号量机制,肯定会涉及到P、V操作6.创建工作环境功能:包括建立共享内存区、连接进程和共享内存区、创建并初始化信号量集、创建子进程模拟5个哲学家等。1.5软件设计的目的:完成对哲学家进餐问题的求解,解决死锁问题。 1.6最终成果:最终要提交的成果是:说明书、源程序(

6、cpp文件)2 总体设计2.1程序模块结构图:图1 哲学家进餐问题程序模块结构图2.2程序流程图2.2.1 总体流程图图2 总体程序流程图2.2.2哲学家进餐问题解决方案流程图图3 哲学家进餐问题解决方案流程图3详细设计3.1 包含必要的头文件由于要调用Linux系统函数,所以要导入必要的头文件,需要导入的头文件如下:#include <sys/types.h> /使用了shmat函数#include <sys/ipc.h>#include <sys/sem.h> /使用了semget函数#include <sys/wait.h> /使用了wai

7、t函数#include <sys/shm.h> /使用了shmget、shmat、shmctl、shmdt四个函数#include <stdio.h> /使用了printf函数#include <string.h>#include <unistd.h>#include <stdlib.h> /使用了exit函数3.2所有用到的常量、全局变量及宏定义/- 宏定义 -#define N 5 /哲学家的人数(叉子个数)#define LEFT (i+N-1)%N /i的左边邻居编号#define RIGHT (i+1)%N /i的右边邻居编

8、号#define THINKING 0 /哲学家在思考#define HUNGRY 1 /哲学家试图拿起叉子#define EATING 2 /哲学家进餐/- 全局变量的定义 -int mutex; /缓冲区信号量(含有1个)int semphilosopher; /哲学家状态信号量(含有5个,用于标记哲学家)char *state; /哲学家状态int shmid; /共享内存区的标识号3.3联合体semun的定义联合体semun用于在对信号量设置和修改值的时候作为semctl函数的最后一个参数。union semun /对信号量控制的命令参数semun int val; /信号量的值 st

9、ruct semid_ds *buf; /IPC_STAT 和 IPC_SET 的缓冲区 ushort *array; /为获得GETALL和设置SETALL信号量值的数组arguement;3.4创建并初始化工作环境模块3.4.1涉及到的Linux系统函数在这个模块中,涉及到很多Linux系统函数的调用,以下是这些重要函数的解释:(1)shmget函数说明:函数原型:int shmget(key_t key, size_t size, int shmflg)函数作用:得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符。参数含义: key:0(IPC_PRIVATE):会建立新共

10、享内存对象 大于0的32位整数:视参数shmflg来确定操作。 size:大于0的整数:新建的共享内存大小,以字节为单位 0:只获取共享内存时指定为0 shmflg:0:取共享内存标识符,若不存在则函数会报错 IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符 IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错返回值:成功:返回共享内存的标识符 出错:-1,错误原因存于error中(2)

11、shmat函数说明:函数原型:void *shmat(int shmid, const void *shmaddr, int shmflg)函数作用:连接共享内存标识符为shmid的共享内存,连接成功后把共享内存区对象映射到调用进程的地址空间,随后可像本地空间一样访问参数含义:shmid 共享内存标识符 shmaddr 指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置 shmflg SHM_RDONLY:为只读模式,其他为读写模式返回值 :成功:附加好的共享内存地址 出错:-1,错误原因存于errno中(3)semget函数说明:函数原型:int s

12、emget(key_t key,int nsems,int semflg);函数作用:获取与某个键关联的信号量集标识参数含义:key:所创建或打开信号量集的键值。 nsems:创建的信号量集中的信号量的个数,该参数只在创建信号量集时有效。 semflg:调用函数的操作类型返回值:成功返回信号量集的IPC标识符,失败返回-1(4)信号量操作模板sem_op定义: struct sembufunsigned short sem_num;short sem_op;short sem_flg; ;当sem_op.sem_op为-1时表示执行P操作,sem_op为1时表示执行V操作3.4.2申请共享内存

13、区/* 函数功能:申请一块新的共享内存区 参数:无 返回值:int,含义是创建共享内存区的结果(成功为1,失败为0)*/int newshm() shmid = shmget(IPC_PRIVATE, N, IPC_CREAT|0660); /申请共享内存区 if(shmid < 0) /shmget函数返回值为-1表示申请失败 return 0; /申请失败,返回0 return 1; /申请成功,返回13.4.3连接共享内存区和进程/* 函数功能:把共享段与本进程连接在一起 参数:无 返回值:int类型,含义是连接操作的结果(成功为1,失败为0)*/int doshmat() sta

14、te = (char*)shmat(shmid,0, 0); /将共享段与本进程连接 if(state = (void*)-1) /连接过程中出错 return 0; /操作失败,返回0 return 1; /操作成功,返回13.4.4创建信号量集并初始化信号量/* 函数功能:创建信号量集并为每个哲学家初始化信号量 参数:无 返回值:int类型,含义是操作的结果(成功为1,失败为0)*/int newsem() /将每个哲学家信号量值初始化为0 arguement.val = 0;/创建一个含有N个哲学家信号量集 semphilosopher = semget(IPC_PRIVATE, N,

15、IPC_CREAT|0660); if(semphilosopher = -1) /创建信号量集失败 printf("创建哲学家信号量集失败!n"); return 0; /操作失败,返回0 printf("->创建哲学家信号量集成功!n");/将每个哲学家信号量的值设置为0 for(int i=0; i<N; i+) /逐一设置信号量的值 if (semctl(semphilosopher,i,SETVAL,arguement) < 0)printf("设置第%d个哲学家的信息失败!n",i+1); return

16、0; /操作失败,返回0 /为了使得访问哲学家信号量集的进程互斥地操作,设置互斥信号量mutex /缓冲区的信号量初始化为1 arguement.val = 1; mutex = semget(IPC_PRIVATE,1,IPC_CREAT|0660);/取得信号量集合标志 if (mutex < 0) return 0; /取得操作失败,返回0 if (semctl(mutex,0,SETVAL,arguement) < 0) return 0; /设置信号量值操作失败,返回0 return 1; /操作成功3.5 实现P、V操作3.5.1涉及到的Linux系统函数(1)semo

17、p函数说明:函数原型:int semop(int semid, struct sembuf *sops, unsigned nsops);函数作用:对信号量执行P、V操作参数含义:semid:信号集的识别码,可通过semget获取(semget返回值)。 sops: 信号量操作模板 nsops:信号操作结构的数量,恒大于或等于1返回值含义:操作结果,正常返回值为0,错误返回-13.5.2实现P操作/* 函数功能:对semid信号量集合的第member个信号量执行P操作 参数:semid 信号量集合的关键字 member 信号量集合中中要操作信号量的索引 返回值:无 */void p_opera

18、tor(int semid, int member)/初始化信号量操作模板sem_op struct sembuf sem_op= member, -1, SEM_UNDO ; semop(semid, &sem_op, 1); /执行对信号量的P操作3.5.3实现V操作/* 函数功能:对semid信号量集合的第member个信号量执行V操作 参数:semid 信号量集合的关键字 member 信号量集合中中要操作信号量的索引 返回值:无 */void v_operator(int semid, int member)/初始化sem_op,当sem_op.sem_op为1时表示执行V操

19、作 struct sembuf sem_op= member, 1, SEM_UNDO ; semop(semid, &sem_op, 1); /执行对信号量的V操作3.6实现哲学家进餐问题解决方案的主要算法3.6.1涉及到的linux系统函数(1)sleep函数函数原型:sleep(unsigned long);函数作用:执行挂起一段时间注意:sleep()单位为秒3.6.2实现哲学家思考功能/* 函数功能:实现第i个哲学家思考的功能 参数:i 第i个哲学家(索引) 返回值:无 */void think(int i) statei = THINKING; /修改哲学家的状态为思考 p

20、rintf("哲学家%d正在思考!n",i+1); sleep(3); /程序暂停执行3秒3.6.2实现哲学家进餐功能/* 函数功能:实现第i个哲学家进餐的功能 参数:i 第i个哲学家(索引) 返回值:无 */void eat(int i) printf("哲学家%d正在进餐!n",i+1); sleep(3); /程序暂停执行3秒3.6.3实现哲学家拿起叉子功能实现拿起叉子前的试探操作(防止死锁算法)/* 函数功能:实现第i个哲学家进餐前的试探功能(防止死锁) 参数:i 第i个哲学家(索引) 返回值:无 */void test(int i

21、) if (statei=HUNGRY && stateLEFT!=EATING && stateRIGHT!=EATING) /左右邻居无人在进餐且哲学家需要进餐 statei = EATING; /修改哲学家的状态为进餐 printf("哲学家%d拿起两把叉子准备进餐!n",i+1); v_operator(semphilosopher, i); /释放对信号量集的控制权 实现拿起叉子功能/* 函数功能:实现第i个哲学家拿起叉子功能(P操作) 参数:i 第i个哲学家(索引) 返回值:无 */void take_forks(i

22、nt i) p_operator(mutex, 0); /申请对互斥信号量的控制权(P) statei = HUNGRY; /修改哲学家的状态为饥饿 test(i); /哲学家试探拿起两把叉子 v_operator(mutex, 0); /释放对互斥信号量的控制权(V) p_operator(semphilosopher, i); /申请对信号量集的控制权3.6.4实现放下叉子功能/* 函数功能:实现第i个哲学家放下叉子功能(V操作) 参数:i 第i个哲学家(索引) 返回值:无 */void put_forks(int i) p_operator(mutex, 0); /申请对互斥信号量的控制

23、权(P) statei = THINKING; /修改状态为“思考” printf("哲学家%d用餐完毕,放下手中的叉子!n",i+1); test(LEFT); /通知左邻居可以进餐了 test(RIGHT); /通知右邻居可以进餐了 v_operator(mutex, 0); /释放对互斥信号量的控制权(V)3.6.5将上述功能整合起来/* 函数功能:实现第i个哲学家进餐问题,调用相关功能的子函数 参数:i 第i个哲学家(索引) 返回值:无 */void philosopher(int i) think(i); /思考 take_forks(i); /拿起叉子 eat(

24、i); /进餐 put_forks(i); /放下叉子 think(i); /继续思考3.7将所有模块连接在一起,形成一套完整的程序为了方便最终的整合,将所有模块的整合调用放进一个单独的函数,供主函数调用,最终程序整合只需调用这个方法。/* 函数功能:为方便最终程序的整合,将功能调用单独做成函数,供主函数调用 参数:无 返回值:无 */int philosopherEatingProblem()printf("-实现信号量通信机制哲学家进餐问题-n");printf("-作者: -n");int current,pc;/1.首先创建一块共享内存区 if(

25、newshm()=0) printf("创建共享内存区失败!n"); return 1; /2.将创建的共享段与进程连接起来,使得进程能操作共享内存区 if(doshmat()=0) printf("共享段与进程连接失败!n"); return 1; /3.创建一个含有5个信号量的信号量集并完成其初始化操作 if(newsem()=0) printf("创建信号量集或对其操作过程中出现错误!n"); return 1; /4.创建N个(哲学家人数)子进程 for(int i=0; i<N; i+) while(pc=fork()

26、<0); /not -1 if(pc = 0) current = i; break; /5.执行哲学家进餐问题的解决方案 if(pc > 0) wait(state);/删除与第一个参数对应的物理存储空间 shmctl(mutex, IPC_RMID, 0); shmctl(semphilosopher, IPC_RMID, 0);/切断逻辑地址与内存的联系 shmdt(state); shmctl(shmid, IPC_RMID, 0); else /对哲学家进餐问题进行求解 philosopher(current);3.8编写主函数/* 函数功能:调用子函数完成对整个问题的求

27、解 参数:无 返回值:int类型,返回0表示程序执行完毕正常退出 */int main() philosopherEatingProblem(); return 0;3.9编写菜单int main()bool flag1=true; /定义标志,用以控制菜单执行char ch;char MainMenu= "ntt 操作系统课程设计:基于Linux的进程之间通信nn" "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *nn" "ttt1

28、.实现管道通信P183 n" "ttt2.实现信号量通信机制 P191 n" "ttt3.实现消息缓冲通信机制 P197 n" "ttt4.实现共享内存区通信机制 P201(2) n" "ttt5.退出系统nn" "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *n" "请选择您想要执行的操作:(请输入1-5中任意一个整数,并按回车确定)"while(flag1)printf(MainMenu); /switch(ch=getchar(),getchar(),ch) switch(ch=getchar(),ch) case '1': hnfifo(); break; / case case '2': philosopherEatingProblem(); break; / case case '3': msgbufferQueue();break; / c

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论