ImageVerifierCode 换一换
格式:DOC , 页数:19 ,大小:588KB ,
资源ID:4316255      下载积分:8 金币
快捷注册下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

开通VIP
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.zixin.com.cn/docdown/4316255.html】到电脑端继续下载(重复下载【60天内】不扣币)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

开通VIP折扣优惠下载文档

            查看会员权益                  [ 下载后找不到文档?]

填表反馈(24小时):  下载求助     关注领币    退款申请

开具发票请登录PC端进行申请

   平台协调中心        【在线客服】        免费申请共赢上传

权利声明

1、咨信平台为文档C2C交易模式,即用户上传的文档直接被用户下载,收益归上传人(含作者)所有;本站仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。所展示的作品文档包括内容和图片全部来源于网络用户和作者上传投稿,我们不确定上传用户享有完全著作权,根据《信息网络传播权保护条例》,如果侵犯了您的版权、权益或隐私,请联系我们,核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
2、文档的总页数、文档格式和文档大小以系统显示为准(内容中显示的页数不一定正确),网站客服只以系统显示的页数、文件格式、文档大小作为仲裁依据,个别因单元格分列造成显示页码不一将协商解决,平台无法对文档的真实性、完整性、权威性、准确性、专业性及其观点立场做任何保证或承诺,下载前须认真查看,确认无误后再购买,务必慎重购买;若有违法违纪将进行移交司法处理,若涉侵权平台将进行基本处罚并下架。
3、本站所有内容均由用户上传,付费前请自行鉴别,如您付费,意味着您已接受本站规则且自行承担风险,本站不进行额外附加服务,虚拟产品一经售出概不退款(未进行购买下载可退充值款),文档一经付费(服务费)、不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
4、如你看到网页展示的文档有www.zixin.com.cn水印,是因预览和防盗链等技术需要对页面进行转换压缩成图而已,我们并不对上传的文档进行任何编辑或修改,文档下载后都不会有水印标识(原文档上传前个别存留的除外),下载后原文更清晰;试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓;PPT和DOC文档可被视为“模板”,允许上传人保留章节、目录结构的情况下删减部份的内容;PDF文档不管是原文档转换或图片扫描而得,本站不作要求视为允许,下载前可先查看【教您几个在下载文档中可以更好的避免被坑】。
5、本文档所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用;网站提供的党政主题相关内容(国旗、国徽、党徽--等)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
6、文档遇到问题,请及时联系平台进行协调解决,联系【微信客服】、【QQ客服】,若有其他问题请点击或扫码反馈【服务填表】;文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“【版权申诉】”,意见反馈和侵权处理邮箱:1219186828@qq.com;也可以拔打客服电话:0574-28810668;投诉电话:18658249818。

注意事项

本文(操作系统课程设计说明书-基于Linux的进程之间通信.doc)为本站上传会员【丰****】主动上传,咨信网仅是提供信息存储空间和展示预览,仅对用户上传内容的表现方式做保护处理,对上载内容不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知咨信网(发送邮件至1219186828@qq.com、拔打电话4009-655-100或【 微信客服】、【 QQ客服】),核实后会尽快下架及时删除,并可随时和客服了解处理情况,尊重保护知识产权我们共同努力。
温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载【60天内】不扣币。 服务填表

操作系统课程设计说明书-基于Linux的进程之间通信.doc

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

2、 (3) 实现消息缓冲通信机制,要求见P197习题。 (4) 实现共享内存区通信机制,要求见P201习题(2)。 要求: (1) 用Linux中进程控制系统调用函数来创建进程(线程)。 (2) 输出进程通信时同步的说明信息。 1.2小组分工我拿到的题目是:(2) 实现信号量通信机制,要求见P191习题(3)。 1.3题目的要求如下: 1.3.1.哲学家进餐问题描述: 设有5个哲学家,共享一张放有5把椅子和5把叉子的圆桌,每人分得一把椅子。哲学家们在肚子饥饿时才试图分两次从两边捡起两把叉子就餐。 条件: 1.每个人只有拿到两把叉子时,哲学家才能吃饭 2.如果叉子已在他

3、人手上,则哲学家必须等到他人吃完后才能拿起叉子 3.任性的哲学家在自己未拿到两把叉子吃饭之前,绝不放下自己手中的叉子 1.3.2问题: 1.什么情况下5个哲学家全部都吃不上饭? 答:当5个哲学家每人手中都拿到了1把叉子(共5把),即不肯放下自己手中的叉子又想要得到左右邻居的叉子时,每个哲学家永远拿不到两把叉子,所有哲学家都在等待另一把叉子,就会导致这5个哲学家谁都吃不上饭。也就是产生死锁后的情况。 2.编程实现没有人饿死(永远拿不到两个叉子)的算法。 答:程序请看代码实现。 分析:没有人饿死,就是不允许出现死锁的情况(5个哲学家每人1把叉子) 1.3.3解决死锁

4、的方法有三种: 1.至多允许四位哲学家同时去拿左边的叉子,最终保证至少有一位哲学家能够进餐,并且在用毕时能释放出他用过的两只叉子,从而使更多哲学家能够进餐; 2.规定当哲学家的左右两只叉子均可用时,才允许他拿起叉子进餐; 3.规定奇数号的哲学家先拿他左边的叉子,然后再去拿他右边的叉子,而偶数号哲学家则相反。五位哲学家都先竞争奇数号叉子,获得后再竞争偶数号叉子,最终总有一位哲学家会因为获得两只叉子而进餐。 1.3.4我采用的解决死锁问题的方法 我采用的解决死锁的方法是第二种,即在哲学家拿起叉子前先判断他左右邻居的情况,只要左右邻居中有一位正在进餐(叉子已经被邻居拿到,邻居进餐结

5、束前自己无法获得其叉子),就不允许其拿起叉子进餐,这就可以预防死锁的情况发生。 1.4软件需要完成的功能: 按照题目要求,需要调用Linux操作系统函数使用信号量机制完成对哲学家进餐问题的求解,要求所有哲学家都能吃到食物,并且要防止哲学家在竞争叉子过程发生死锁。 程序应该包含如下功能: 1.哲学家思考功能:哲学家在进餐前和进餐后处于思考状态; 2.哲学家拿起叉子动能:哲学家进餐前需要拿起叉子,在这个过程中可能发生死锁,所以要在这个功能中编写防止死锁的方法; 3.哲学家进餐功能:哲学家拿起叉子后开始进餐; 4.哲学家放下叉子功能:哲学家用餐完毕,放下叉子,并通知其左右邻居; 5.

6、执行P、V操作功能:由于要使用信号量机制,肯定会涉及到P、V操作 6.创建工作环境功能:包括建立共享内存区、连接进程和共享内存区、创建并初始化信号量集、创建子进程模拟5个哲学家等。 1.5软件设计的目的: 完成对哲学家进餐问题的求解,解决死锁问题。 1.6最终成果: 最终要提交的成果是:说明书、源程序(cpp文件) 2 总体设计 2.1程序模块结构图: 图1 哲学家进餐问题程序模块结构图 2.2程序流程图 2.2.1 总体流程图 图2 总体程序流程图 2.2.2哲学家进餐问题解决方案流程图 图3 哲学家进餐问题解决方案流程图 3.详细设

7、计 3.1 包含必要的头文件 由于要调用Linux系统函数,所以要导入必要的头文件,需要导入的头文件如下: #include //使用了shmat函数 #include #include //使用了semget函数 #include //使用了wait函数 #include //使用了shmget、shmat、shmctl、shmdt四个函数 #include //

8、使用了printf函数 #include #include #include //使用了exit函数 3.2所有用到的常量、全局变量及宏定义 //---------------------------- 宏定义 ---------------------------------- #define N 5 //哲学家的人数(叉子个数) #define LEFT (i+N-1)%N //i的左边邻居编号 #define RIGHT (i+1)%N //i的右边邻

9、居编号 #define THINKING 0 //哲学家在思考 #define HUNGRY 1 //哲学家试图拿起叉子 #define EATING 2 //哲学家进餐 //-------------------------- 全局变量的定义 -------------------------------- int mutex; //缓冲区信号量(含有1个) int semphilosopher; //哲学家状态信号量(含有5个,用于标记哲学家) char *state; //哲学

10、家状态 int shmid; //共享内存区的标识号 3.3联合体semun的定义 联合体semun用于在对信号量设置和修改值的时候作为semctl函数的最后一个参数。 union semun { //对信号量控制的命令参数semun int val; //信号量的值 struct semid_ds *buf; //IPC_STAT 和 IPC_SET 的缓冲区 ushort *array; //为获得GETALL和设置SETALL信号量值的数组 }argueme

11、nt; 3.4创建并初始化工作环境模块 3.4.1涉及到的Linux系统函数 在这个模块中,涉及到很多Linux系统函数的调用,以下是这些重要函数的解释: (1)shmget函数说明: 函数原型:int shmget(key_t key, size_t size, int shmflg) 函数作用:得到一个共享内存标识符或创建一个共享内存对象并返回共享内存标识符。 参数含义: key:0(IPC_PRIVATE):会建立新共享内存对象 大于0的32位整数:视参数shmflg来确定操作。 size:大于0的整数:新建的共享内存大小,

12、以字节为单位 0:只获取共享内存时指定为0 shmflg:0:取共享内存标识符,若不存在则函数会报错 IPC_CREAT:当shmflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存,返回此共享内存的标识符 IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的共享内存,则新建一个共享内存;如果存在这样的共享内存则报错 返回值:成功:返回共享内存的标识符 出错:-1,错误原因存于error中 (2)shmat函数说明: 函数原型:void *shmat(i

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

14、et(key_t key,int nsems,int semflg); 函数作用:获取与某个键关联的信号量集标识 参数含义:key:所创建或打开信号量集的键值。 nsems:创建的信号量集中的信号量的个数,该参数只在创建信号量集时有效。 semflg:调用函数的操作类型 返回值:成功返回信号量集的IPC标识符,失败返回-1 (4)信号量操作模板sem_op定义: struct sembuf{ unsigned short sem_num; short sem_op; short sem_flg; }; 当sem_op.sem_op为-

15、1时表示执行P操作,sem_op为1时表示执行V操作 3.4.2申请共享内存区 /* 函数功能:申请一块新的共享内存区 参数:无 返回值:int,含义是创建共享内存区的结果(成功为1,失败为0)*/ int newshm(){ shmid = shmget(IPC_PRIVATE, N, IPC_CREAT|0660); //申请共享内存区 if(shmid < 0){ //shmget函数返回值为-1表示申请失败 return 0; //申请失败,返回0 } return 1; //申请成功,返回1

16、} 3.4.3连接共享内存区和进程 /* 函数功能:把共享段与本进程连接在一起 参数:无 返回值:int类型,含义是连接操作的结果(成功为1,失败为0)*/ int doshmat(){ state = (char*)shmat(shmid,0, 0); //将共享段与本进程连接 if(state == (void*)-1){ //连接过程中出错 return 0; //操作失败,返回0 } return 1; //操作成功,返回1 } 3.4.4创建信号量集并初始化信号量 /* 函数功能:创建信号量

17、集并为每个哲学家初始化信号量 参数:无 返回值:int类型,含义是操作的结果(成功为1,失败为0)*/ int newsem(){ //将每个哲学家信号量值初始化为0 arguement.val = 0; //创建一个含有N个哲学家信号量集 semphilosopher = semget(IPC_PRIVATE, N, IPC_CREAT|0660); if(semphilosopher == -1) { //创建信号量集失败 printf("创建哲学家信号量集失败!\n"); return 0; //操

18、作失败,返回0 } printf("->创建哲学家信号量集成功!\n"); //将每个哲学家信号量的值设置为0 for(int i=0; i

19、信号量初始化为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)semop函数说明:

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

21、要操作信号量的索引 返回值:无 */ void p_operator(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 信号量集合中中要操作信号量的索引

22、 返回值:无 */ void v_operator(int semid, int member){ //初始化sem_op,当sem_op.sem_op为1时表示执行V操作 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(

23、)单位为秒 3.6.2实现哲学家思考功能 /* 函数功能:实现第i个哲学家思考的功能 参数:i 第i个哲学家(索引) 返回值:无 */ void think(int i){ state[i] = THINKING; //修改哲学家的状态为思考 printf("哲学家%d正在思考!\n",i+1); sleep(3); //程序暂停执行3秒 } 3.6.2实现哲学家进餐功能 /* 函数功能:实现第i个哲学家进餐的功能 参数:i 第i个哲学家(索引) 返回值:无 */ void eat(int i){

24、printf("哲学家%d正在进餐!\n",i+1); sleep(3); //程序暂停执行3秒 } 3.6.3实现哲学家拿起叉子功能 3.6.3.1实现拿起叉子前的试探操作(防止死锁算法) /* 函数功能:实现第i个哲学家进餐前的试探功能(防止死锁) 参数:i 第i个哲学家(索引) 返回值:无 */ void test(int i){ if (state[i]==HUNGRY && state[LEFT]!=EATING && state[RIGHT]!=EATING){ //左右邻居无人在进餐且哲学家需要进餐

25、 state[i] = EATING; //修改哲学家的状态为进餐 printf("哲学家%d拿起两把叉子准备进餐!\n",i+1); v_operator(semphilosopher, i); //释放对信号量集的控制权 } } 3.6.3.2实现拿起叉子功能 /* 函数功能:实现第i个哲学家拿起叉子功能(P操作) 参数:i 第i个哲学家(索引) 返回值:无 */ void take_forks(int i){ p_operator(mutex, 0); //申请对互斥信号量的控制权(P

26、 state[i] = 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_oper

27、ator(mutex, 0); //申请对互斥信号量的控制权(P) state[i] = THINKING; //修改状态为“思考” printf("哲学家%d用餐完毕,放下手中的叉子!\n",i+1); test(LEFT); //通知左邻居可以进餐了 test(RIGHT); //通知右邻居可以进餐了 v_operator(mutex, 0); //释放对互斥信号量的控制权(V) } 3.6.5将上述功能整合起来 /* 函数功能:实现第i个哲学家进餐问题,调用相关功能的子函数

28、参数:i 第i个哲学家(索引) 返回值:无 */ void philosopher(int i){ think(i); //思考 take_forks(i); //拿起叉子 eat(i); //进餐 put_forks(i); //放下叉子 think(i); //继续思考 } 3.7将所有模块连接在一起,形成一套完整的程序 为了方便最终的整合,将所有模块的整合调用放进一个单独的函数,供主函数调用,最终程序整合只需调用这个方法。 /* 函数功能:为方便最终程序的整合,将功能调用

29、单独做成函数,供主函数调用 参数:无 返回值:无 */ int philosopherEatingProblem(){ printf("---------------实现信号量通信机制——哲学家进餐问题-----------------\n"); printf("---------------作者: -----------------\n"); int current,pc; //1.首先创建一块共享内存区 if(newshm()==0){ printf("创建共享内存区失败!\n"); return 1;

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

31、 while((pc=fork())<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); //切断逻辑地址与

32、内存的联系 shmdt(state); shmctl(shmid, IPC_RMID, 0); } else //对哲学家进餐问题进行求解 philosopher(current); } 3.8编写主函数 /* 函数功能:调用子函数完成对整个问题的求解 参数:无 返回值:int类型,返回0表示程序执行完毕正常退出 */ int main(){ philosopherEatingProblem(); return 0; } 3.9编写菜单 int main(){ bo

33、ol flag1=true; //定义标志,用以控制菜单执行 char ch; char MainMenu[]= "\n\t\t 操作系统课程设计:基于Linux的进程之间通信\n\n" "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **\n\n" "\t\t\t1.实现管道通信P183 \n" "\t\t\t2.实现信号量通信机制 P191 \n" "\t\t\t3.实现消息

34、缓冲通信机制 P197 \n" "\t\t\t4.实现共享内存区通信机制 P201(2) \n" "\t\t\t5.退出系统\n\n" "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * **\n" "请选择您想要执行的操作:(请输入1-5中任意一个整数,并按回车确定)"; while(flag1){ printf(MainMenu); //switch(ch=getchar(),getchar(),ch){

35、 switch(ch=getchar(),ch){ case '1':{ hnfifo(); break; }// case case '2':{ philosopherEatingProblem(); break; }// case case '3':{ msgbufferQueue();break; }// case case '4':{ sharememory();br

36、eak; }// case case '5':{ printf("\t\t\t\t谢谢使用,再见!\n"); //退出功能 exit(0); }// case default:{ printf("您输入了非法信息,请重新输入!\n"); //提示用户输入非法 break; }//default }//switch getchar();getchar(); fflush(stdin); //清空缓冲区,避免多输入的

37、字符影响菜单运行 }//while return 0; }//main 3.10运行结果 使用终端编译,结果如下: 4.心得体会 通过本次课程设计我学到了很多,下面谈一谈我的收获: (1)团队合作方面:本次课程设计过程中由于我们分工明确,任务下达清楚,大家都知道自己该做什么,都朝着正确的方向在努力,所以收到了比较好的效果,效率也较高,这使我明白了,在以后的分工合作过程中,合理的分工和明确的任务的重要性。 (2)程序设计方面:本次课程设计过程中我遇到了很多挑战: 首先是

38、来自题目的挑战,因为自己从来没用过Linux操作系统,所以看到题目后很担心自己会完不成任务,但是最后我还是下决心从0开始,网上的Linux版本花样繁多,不知道该选择那个号,历经很多次失败后,终于成功从网上下载了Red Hat Enterprise Linux 6版本并安装成功了程序的编译环境(gcc)和运行环境(Eclipse C++),并成功编译了Linux上的第一个C++程序。这次经历使我感受到了自学能力的重要性。在如今的环境下,IT技术更新速度飞快,所以自学能力就显得尤为重要,这次自学安装配置Linux环境,编译自己写的源代码的过程中我感觉到Linux的用法和Mac OS X操作系统十分相似,很多操作是相通的,这也体现了知识之间是相互联系的,因为Linux和Mac OS X操作系统使用的都是UNIX内核,所以有所相似很正常。 其次是来自技术方面的挑战,很多之前在windows上使用的语句在linux下也发生了改变,导致我在做菜单的时候很多操作都不起作用,这提醒了我以后要注意程序的可移植性。 这次课设对我的帮助很大,今后我会再接再厉,努力做好每份程序。 18

移动网页_全站_页脚广告1

关于我们      便捷服务       自信AI       AI导航        抽奖活动

©2010-2026 宁波自信网络信息技术有限公司  版权所有

客服电话:0574-28810668  投诉电话:18658249818

gongan.png浙公网安备33021202000488号   

icp.png浙ICP备2021020529号-1  |  浙B2-20240490  

关注我们 :微信公众号    抖音    微博    LOFTER 

客服