




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、精选优质文档-倾情为你奉上计算机科学与技术学院操作系统实验报告实验题目:理发店问题 理发店问题:假设理发店的理发室中有3个理发椅子和3个理发师,有一个可容纳4个顾客坐等理发的沙发。此外还有一间等候室,可容纳13位顾客等候进入理发室。顾客如果发现理发店中顾客已满(超过20人),就不进入理发店。在理发店内,理发师一旦有空就为坐在沙发上等待时间最长的顾客理发,同时空出的沙发让在等候室中等待时间最长的的顾客就坐。顾客理完发后,可向任何一位理发师付款。但理发店只有一本现金登记册,在任一时刻只能记录一个顾客的付款。理发师在没有顾客的时候就坐在理发椅子上睡眠。理发师的时间就用在理发、收款、睡眠上。请利用li
2、nux系统提供的IPC进程通信机制实验并实现理发店问题的一个解法。实验目的: 进一步研究和实践操作系统中关于并发进程同步与互斥操作的一些经典问题的解法,加深对于非对称性互斥问题有关概念的理解。观察和体验非对称性互斥问题的并发控制方法。进一步了解Linux系统中IPC进程同步工具的用法,训练解决对该类问题的实际编程、调试和分析问题的能力。硬件环境: Inter(R)Core(TM)i5-3210M CPU 2.50GHz 内存:4GB 硬盘:500G软件环境: XUbuntuLinux 操作系统 Gnome 桌面 2.18.3 BASH_VERSION=3.2.33(1)-release gcc
3、 version 4.1.2 gedit 2.18.2 OpenOffice 2.3 实验步骤: 1、问题分析: 为了解决本实验的同步问题,采用共享内存,信号量,消 息队列三种IPC 同步对象处理。 客户程序思想: 每一个客户把自己的请求当做一条消息发送到相应的消息 队列中去,并通过阻塞等待接收消息的方式来等待理发师 最终帮自己理发。每一个客户先判断sofa 是不是坐满了,如 果没有就坐在沙发上等,否者就判断waitroom 是不是坐满 了,如果没有,就坐在waitroom 等,只要有一个坐在sofa 的客户离开sofa 理发,理发师就会到waitroom 找最先来的 客户,让他进入sofa
4、等待。 理发师程序思想: 理发师查看sofa 上有没有人,没有就睡3 秒,然后再一次 看有没有人,如果有人,就到沙发请最先来的客户来理发。 账本互斥的实现: Semaphore mutex=1 ; Sofa 队列的长度和wait 队列的长度的实现: 在顾客进程中设置两个变量sofa_count,wait_count,分别保存沙发和等候室的顾客数。2、算法设计说明如下:该解法利用消息队列的每条消息代表每个顾客,将进入等候室的顾客组织到一个队列,将坐入沙发的顾客组织到另一个队列。理发师从沙发队列请出顾客,空出的沙发位置再从等候室请入顾客进入沙发队列。三个理发师进程使用相同的程序段上下文,所有顾客使
5、用同一个程序段上下文。这样可避免产生太多进程,以便节省系统资源。理发师程序(Barber)建立一个互斥帐本信号量:s_account,初值=1;建立一个同步顾客信号量:s_customer,初值=0;建立沙发消息队列:q_sofa;建立等候室消息队列:q_wait;建立3个理发师进程:b1_pid, b2_pid, b3_pid;每个理发师进程作:while(1)以阻塞方式从沙发队列接收一条消息,如果有消息,则消息出沙发队列(模拟一顾客理发);唤醒顾客进程(让下一顾客坐入沙发)。用进程休眠一个随机时间模拟理发过程。理完发,使用帐本信号量记账。互斥的获取账本记账唤醒用账本理发师者否则没有消息(沙
6、发上无顾客)则理发师进程在沙发队列上睡眠;当沙发队列有消息时被唤醒(有顾客坐入沙发)。顾客程序(customer)while(1)取沙发队列消息数(查沙发上顾客数) ;如果消息数小于4(沙发没座满)以非阻塞方式从等候室队列接收一条消息(查等候室有顾客否),如果有消息将接收到的消息发送到沙发队列(等候室顾客坐入沙发);否则发送一条消息到沙发队列(新来的顾客直接坐入沙发);否则(沙发坐满)取等候室队列消息数(查等候室顾客数) ;如果消息数小于13发送一条消息到等候室队列(等候室没满,新顾客进等候室);否则在顾客同步信号量上睡眠(等候室满暂不接待新顾客);用进程休眠一个随机时间模拟顾客到达的时间间隔
7、。3、 开发调试过程:在shell命令行下运行$ make barber customergcc -g -c barber.c ipc.cgcc barber.o ipc.o -o barbergcc -g -c customer.c ipc.cgcc customer.o ipc.o -o customer假设先运行理发师程序:$ ./barber 2726号理发师睡眠2728号理发师睡眠2727号理发师睡眠运行$./customer1号新顾客坐入沙发2号新顾客坐入沙发3号新顾客坐入沙发4号新顾客坐入沙发5号新顾客坐入沙发6号新顾客坐入沙发7号新顾客坐入沙发8号新顾客坐入沙发9号新顾客坐入沙
8、发10号新顾客坐入沙发11号新顾客坐入沙发12号新顾客坐入沙发沙发坐满13号顾客在等候室等候13号顾客从等候室坐入沙发沙发坐满14号顾客在等候室等候14号顾客从等候室坐入沙发沙发坐满15号顾客在等候室等候15号顾客从等候室坐入沙发沙发坐满16号顾客在等候室等候16号顾客从等候室坐入沙发17号新顾客坐入沙发沙发坐满18号顾客在等候室等候18号顾客从等候室坐入沙发沙发坐满19号顾客在等候室等候19号顾客从等候室坐入沙发沙发坐满20号顾客在等候室等候20号顾客从等候室坐入沙发沙发坐满21号顾客在等候室等候21号顾客从等候室坐入沙发.在理发师窗体理发师进程被唤醒:2726号理发师为1号顾客理发2726
9、号理发师收取1号顾客交费2726号理发师睡眠2728号理发师为2号顾客理发2728号理发师收取2号顾客交费2728号理发师睡眠2727号理发师为3号顾客理发2726号理发师为4号顾客理发2727号理发师收取3号顾客交费2727号理发师睡眠2726号理发师收取4号顾客交费2726号理发师睡眠2728号理发师为5号顾客理发2728号理发师收取5号顾客交费2728号理发师睡眠2727号理发师为6号顾客理发2726号理发师为7号顾客理发2727号理发师收取6号顾客交费2727号理发师睡眠2726号理发师收取7号顾客交费2726号理发师睡眠2728号理发师为8号顾客理发2728号理发师收取8号顾客交费.
10、反之,如果先运行顾客程序:$ ./customer1号新顾客坐入沙发2号新顾客坐入沙发3号新顾客坐入沙发4号新顾客坐入沙发沙发坐满5号顾客在等候室等候沙发坐满6号顾客在等候室等候沙发坐满7号顾客在等候室等候沙发坐满8号顾客在等候室等候沙发坐满9号顾客在等候室等候沙发坐满10号顾客在等候室等候沙发坐满11号顾客在等候室等候沙发坐满12号顾客在等候室等候沙发坐满13号顾客在等候室等候沙发坐满14号顾客在等候室等候沙发坐满15号顾客在等候室等候沙发坐满16号顾客在等候室等候沙发坐满17号顾客在等候室等候等候室满18号顾客没有进入理发店当18号顾客到达时理发店20个位置已满,顾客进程阻塞(假设理发师进
11、程没运行表示三个理发师正坐在3个理发椅上睡觉) 。再运行理发师程序:$ ./barber 运行截图如下:附件:4.7.分析与感悟:首先运行顾客程序的话,顾客程序首先向沙发队列发送消息,然后向等候室队列发送消息,当两个队列都满了之后,该进程会暂停,及停止在顾客同步信号量上。而随着理发师程序的开始运行,理发师进程会唤醒顾客进程,及在顾客同步信号量上进行up操作,并且从消息队列中接受消息。反之,若理发师程序先运行,则三个理发师由于无法从沙发队列上接收到消息,而且由于是阻塞式接受,就会阻塞在这个消息队列上,只有当顾客程序运行时,向沙发队列发送消息后理发师进程才会继续。通过编写这个实验,是我更加熟练了信
12、号量的使用,明白了消息队列的使用方法,进一步了解了Linux系统中IPC进程同步工具的用法。附件:Ipc.c#include ipc.h int get_ipc_id(char *proc_file,key_t key)FILE *pf;int i,j;char lineBUFSZ,columBUFSZ;if(pf = fopen(proc_file,r) = NULL)perror(Proc file not open);exit(EXIT_FAILURE);fgets(line, BUFSZ, pf);while(!feof(pf)i = j = 0;fgets(line, BUFSZ,p
13、f);while(linei = ) i+;while(linei != ) columj+ = linei+;columj = 0;if(atoi(colum) != key) continue;j=0;while(linei = ) i+;while(linei != ) columj+ = linei+;columj = 0;i = atoi(colum);fclose(pf);return i;fclose(pf);return -1; int down(int sem_id)struct sembuf buf;buf.sem_op = -1;buf.sem_num = 0;buf.s
14、em_flg = SEM_UNDO;if(semop(sem_id,&buf,1) 0) perror(down error );exit(EXIT_FAILURE);return EXIT_SUCCESS;int up(int sem_id)struct sembuf buf;buf.sem_op = 1;buf.sem_num = 0;buf.sem_flg = SEM_UNDO;if(semop(sem_id,&buf,1) 0) perror(up error );exit(EXIT_FAILURE);return EXIT_SUCCESS; int set_sem(key_t sem
15、_key,int sem_val,int sem_flg)int sem_id;Sem_uns sem_arg;/测试由 sem_key 标识的信号灯数组是否已经建立if(sem_id = get_ipc_id(/proc/sysvipc/sem,sem_key) 0 )/semget 新建一个信号灯,其标号返回到 sem_idif(sem_id = semget(sem_key,1,sem_flg) 0)perror(semaphore create error);exit(EXIT_FAILURE);/设置信号灯的初值sem_arg.val = sem_val;if(semctl(sem_
16、id,0,SETVAL,sem_arg) 0)perror(semaphore set error);exit(EXIT_FAILURE);return sem_id; char * set_shm(key_t shm_key,int shm_num,int shm_flg)int i,shm_id;char * shm_buf;/测试由 shm_key 标识的共享内存区是否已经建立if(shm_id = get_ipc_id(/proc/sysvipc/shm,shm_key) 0 )/shmget 新建 一个长度为 shm_num 字节的共享内存,其标号返回到 shm_idif(shm_i
17、d = shmget(shm_key,shm_num,shm_flg) 0)perror(shareMemory set error);exit(EXIT_FAILURE);/shmat 将由 shm_id 标识的共享内存附加给指针 shm_bufif(shm_buf = (char *)shmat(shm_id,0,0) (char *)0)perror(get shareMemory error);exit(EXIT_FAILURE);for(i=0; ishm_num; i+) shm_bufi = 0; /初始为 0/shm_key 标识的共享内存区已经建立,将由 shm_id 标识的
18、共享内存附加给指针 shm_bufif(shm_buf = (char *)shmat(shm_id,0,0) (char *)0)perror(get shareMemory error);exit(EXIT_FAILURE);return shm_buf; int set_msq(key_t msq_key,int msq_flg)int msq_id;/测试由 msq_key 标识的消息队列是否已经建立if(msq_id = get_ipc_id(/proc/sysvipc/msg,msq_key) 0 )/msgget 新建一个消息队列,其标号返回到 msq_idif(msq_id =
19、 msgget(msq_key,msq_flg) 0)perror(messageQueue set error);exit(EXIT_FAILURE);return msq_id;Ipc.h:#include #include #include #include #include #include #include #define BUFSZ 256#define MAXVAL 100#define STRSIZ 8#define WRITERQUEST 1#define READERQUEST 2#define FINISHED 3 /写请求标识 /读请求标识/读写完成标识 typedef
20、 union semuns int val; Sem_uns; typedef struct msgbuf long mtype;int mid; Msg_buf; /信号量key_t costomer_key;int costomer_sem;key_t account_key;int account_sem; int sem_val;int sem_flg; /消息队列int wait_quest_flg;key_t wait_quest_key;int wait_quest_id;int wait_respond_flg;key_t wait_respond_key;int wait_r
21、espond_id; int sofa_quest_flg;key_t sofa_quest_key;int sofa_quest_id;int sofa_respond_flg;key_t sofa_respond_key;int sofa_respond_id; int get_ipc_id(char *proc_file,key_t key);char *set_shm(key_t shm_key,int shm_num,int shm_flag);int set_msq(key_t msq_key,int msq_flag);int set_sem(key_t sem_key,int
22、sem_val,int sem_flag);int down(int sem_id);int up(int sem_id);Barber.c:#include ipc.hint main(int argc,char *argv) / int i; int rate; Msg_buf msg_arg; /可在在命令行第一参数指定一个进程睡眠秒数,以调解进程执行速度 if(argv1 != NULL) rate = atoi(argv1); else rate = 3; /联系一个请求消息队列 wait_quest_flg = IPC_CREAT| 0644; wait_quest_key = 1
23、01; wait_quest_id = set_msq(wait_quest_key,wait_quest_flg); /联系一个响应消息队列 wait_respond_flg = IPC_CREAT| 0644; wait_respond_key = 102; wait_respond_id = set_msq(wait_respond_key,wait_respond_flg); /联系一个请求消息队列 sofa_quest_flg = IPC_CREAT| 0644; sofa_quest_key = 201; sofa_quest_id = set_msq(sofa_quest_key
24、,sofa_quest_flg); /联系一个响应消息队列 sofa_respond_flg = IPC_CREAT| 0644; sofa_respond_key = 202; sofa_respond_id = set_msq(sofa_respond_key,sofa_respond_flg); /信号量使用的变量 costomer_key = 301;/顾客同步信号灯键值 account_key = 302;/账簿互斥信号灯键值 sem_flg = IPC_CREAT | 0644; /顾客同步信号灯初值设为0 sem_val = 0; /获取顾客同步信号灯,引用标识存 costome
25、r_sem costomer_sem = set_sem(costomer_key,sem_val,sem_flg); /账簿互斥信号灯初值设为 1 sem_val = 1; /获取消费者同步信号灯,引用标识存 cons_sem account_sem = set_sem(account_key,sem_val,sem_flg); int pid1, pid2; pid1=fork(); if(pid1=0) while(1) / wait_quest_flg=IPC_NOWAIT; printf(%d号理发师睡眠n, getpid(); wait_quest_flg=0; if(msgrcv
26、(sofa_quest_id, &msg_arg, sizeof(msg_arg), 0, wait_quest_flg)=0) msgsnd(sofa_respond_id, &msg_arg,sizeof(msg_arg), 0); printf(%d号理发师为%d号顾客理发n, getpid(), msg_arg.mid); sleep(rate); down(account_sem); printf(%d号理发师收取%d号顾客交费n, getpid(), msg_arg.mid); up(account_sem); else pid2=fork(); if(pid2=0) while(
27、1) / wait_quest_flg=IPC_NOWAIT; printf(%d号理发师睡眠n, getpid(); wait_quest_flg=0; if(msgrcv(sofa_quest_id, &msg_arg, sizeof(msg_arg), 0, wait_quest_flg)=0) msgsnd(sofa_respond_id, &msg_arg,sizeof(msg_arg), 0); printf(%d号理发师为%d号顾客理发n, getpid(), msg_arg.mid); sleep(rate); down(account_sem); printf(%d号理发师收
28、取%d号顾客交费n, getpid(), msg_arg.mid); up(account_sem); else printf(%d号理发师睡眠n, getpid(); else while(1) / wait_quest_flg=IPC_NOWAIT; printf(%d号理发师睡眠n, getpid(); wait_quest_flg=0; if(msgrcv(sofa_quest_id, &msg_arg, sizeof(msg_arg), 0, wait_quest_flg)=0) msgsnd(sofa_respond_id, &msg_arg,sizeof(msg_arg), 0)
29、; printf(%d号理发师为%d号顾客理发n, getpid(), msg_arg.mid); sleep(rate); down(account_sem); printf(%d号理发师收取%d号顾客交费n, getpid(), msg_arg.mid); up(account_sem); else printf(%d号理发师睡眠n, getpid(); return 0;Customer.c:#include ipc.hint main(int argc,char *argv) int rate; Msg_buf msg_arg; /可在在命令行第一参数指定一个进程睡眠秒数,以调解进程执行速度 if(argv1 != NULL) rate = atoi(argv1); else rate = 3; /联系一个请求消息队列 wait_quest_flg = IPC_CREAT| 0644; wait_quest_key = 101; wait_quest_id = set_msq(wait_quest_key,wait_quest_flg); /联系一个响应消息队列 wait_respond_flg = IPC_CREAT| 0644; wait_respond_key = 102; wait_respond_id = set_msq(wait_r
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 出纳实务网课试题及答案
- 初级财务考试题库及答案
- 动态广告设计的创作试题及答案
- 全面掌握国际商业美术设计师考试试题及答案原则
- 餐饮hr面试题目及答案
- 2024年纺织品检验员考试挑战试题及答案
- 2024年助理广告师考试细节注意试题及答案
- 2024广告设计师考试常见误区分析试题及答案
- 安全监理考核试题及答案
- 商业美术设计师创意资源利用试题及答案
- 素养为本的教学评一体化教学设计核心理念
- 译林版三年级上册英语书单词表
- 康复科并发症二次残疾
- (新版)拖拉机驾驶证科目一知识考试题库500题(含答案)
- 2025年中考物理一轮复习:物理学与社会发展 专项练习
- DL∕T 526-2013 备用电源自动投入装置技术条件
- 2024年北京大兴区九年级初三一模英语试题和答案
- 食品生物化学 知到智慧树网课答案
- 2024年江苏国信新丰海上风力发电有限公司招聘笔试冲刺题(带答案解析)
- 学术交流英语(学术写作)智慧树知到期末考试答案2024年
- 国家卫生部《综合医院分级管理标准》
评论
0/150
提交评论