山东大学操作系统实验5进程互斥实验.docx
- 文档编号:6289544
- 上传时间:2023-01-05
- 格式:DOCX
- 页数:18
- 大小:275.94KB
山东大学操作系统实验5进程互斥实验.docx
《山东大学操作系统实验5进程互斥实验.docx》由会员分享,可在线阅读,更多相关《山东大学操作系统实验5进程互斥实验.docx(18页珍藏版)》请在冰豆网上搜索。
山东大学操作系统实验5进程互斥实验
计算机科学与技术学院实验报告
实验题目:
实验五.进程互斥实验
学号:
日期:
2014.4
班级:
计基地12
姓名:
实验目的:
进一步研究和实践操作系统中关于并发进程同步与互斥操作的一些经典问题的解法,加深对于非对称性互斥问题有关概念的理解。
观察和体验非对称性互斥问题的并发控制方法。
进一步了解Linux系统中IPC进程同步工具的用法,训练解决对该类问题的实际编程、调试和分析问题的能力。
实验要求:
理发店问题:
假设理发店的理发室中有3个理发椅子和3个理发师,有一个可容纳4个顾客坐等理发的沙发。
此外还有一间等候室,可容纳13位顾客等候进入理发室。
顾客如果发现理发店中顾客已满(超过20人),就不进入理发店。
在理发店内,理发师一旦有空就为坐在沙发上等待时间最长的顾客理发,同时空出的沙发让在等候室中等待时间最长的的顾客就坐。
顾客理完发后,可向任何一位理发师付款。
但理发店只有一本现金登记册,在任一时刻只能记录一个顾客的付款。
理发师在没有顾客的时候就坐在理发椅子上睡眠。
理发师的时间就用在理发、收款、睡眠上。
总结和分析示例实验和独立实验中观察到的调试和运行信息,说明您对与解决非对称性互斥操作的算法有哪些新的理解和认识?
为什么会出现进程饥饿现象?
本实验的饥饿现象是怎样表现的?
怎样解决并发进程间发生的饥饿现象?
您对于并发进程间使用消息传递解决进程通信问题有哪些新的理解和认识?
根据实验程序、调试过程和结果分析写出实验报告。
硬件环境:
内存:
1G
操作系统:
32位
磁盘:
32G
软件环境:
ubuntu11.02
gcc4.8
实验步骤:
1、了解实验目的,掌握与进程间通信IPC中的3个对象:
共享内存、信号灯数组、消息队列及有关的系统调用,并熟练掌握。
2、阅读实验题目并分析实验的需求。
实验题目:
理发店问题
(1)首先创建ipc.h文件,在里面定义生产者/消费者共用的IPC函数的原型和变量。
(2)然后创建ipc.c文件,在里面定义生产者/消费者共用的IPC的具体的相应函数。
(3)声明两个消息队列,当沙发空闲时则会将空闲的消息放入相应的队列中,让顾客可以进入沙发中,当理发师空闲时,也会将相应的消息放入队列中,从而可以让顾客到理发椅上进行理发。
(4)在消息队列中实现,当等待室里的人数少于十三个时,若从消息队列中获得信息,则顾客可以进入,当沙发上有空位时,在等待室的人可以进入沙发等待。
(5)创建customer文件cons,里面声明两个消息队列,当获得允许进入的信息时,顾客进入等待室,当顾客理完发则会离开,同时向消息队列中发送信息。
(6)创建barbour文件bar,在里面声明三个队列,当理发师就绪则会向队列中发送消息,若顾客收到消息就会去理发,当顾客离开时,也会向队列中发送一条消息。
同时理发师理发与收账是互斥的。
通过上述的文件就可以实现相应的功能。
3、分析清楚实验要求,便开始用编程语言进行编程,将分析的思路用编程语言实现。
4、完成编写程序,要进行运行调试,找到编写中的错误,进行进一步的修改,直到程序运行过程中不再出现错误。
5、完成程序的调试与修改,保存程序,对编程的过程进行总结,找到编程中的不足,并完成实验报告。
实现方式:
编写以下文件直接在命令行
Makefile:
hdrs=ipc.h
opts=-g-c
c_src=cons.cipc.c
c_obj=cons.oipc.o
p_src=bar.cipc.c
p_obj=bar.oipc.o
all:
producerconsumer
consumer:
$(c_obj)
gcc$(c_obj)-oconsumer
cons.o:
$(c_src)$(hdrs)
gcc$(opts)$(c_src)
producer:
$(p_obj)
gcc$(p_obj)-oproducer
bar.o:
$(p_src)$(hdrs)
gcc$(opts)$(p_src)
clean:
rmconsbar*.o
ipc.h:
#include
#include
#include
#include
#include
#include
#include
#defineBUFSZ256
intget_ipc_id(char*proc_file,key_tkey);
char*set_shm(key_tshm_key,intshm_num,intshm_flag);
intset_msq(key_tmsq_key,intmsq_flag);
intset_sem(key_tsem_key,intsem_val,intsem_flag);
intdown(intsem_id);
intup(intsem_id);
/*
信号灯控制用的共同体
*/
typedefunionsemuns{
intval;
}Sem_uns;
typedefstructmsgbuf{
longmtype;
charmtext[1];
}Msg_buf;
key_tbuff_key[2];
intbuff_num;
int*buff_ptr[2];
key_tpput_key[2];
intpput_num;
int*pput_ptr[2];
key_tprod_key;
key_tpmtx_key;
intprod_sem;
intpmtx_sem;
key_tcons_key;
key_tcmtx_key;
intcons_sem;
intcmtx_sem;
intsem_val;
intsem_flg;
intshm_flg;
ipc.c:
#include"ipc.h"
intget_ipc_id(char*proc_file,key_tkey){
FILE*pf;
inti,j;
charline[BUFSZ],colum[BUFSZ];
if((pf=fopen(proc_file,"r"))==NULL){
perror("Procfilenotopen");
exit(EXIT_FAILURE);
}
fgets(line,BUFSZ,pf);
while(!
feof(pf)){
i=j=0;
fgets(line,BUFSZ,pf);
while(line[i]=='')
i++;
while(line[i]!
='')
colum[j++]=line[i++];
colum[j]='\0';
if(atoi(colum)!
=key)
continue;
j=0;
while(line[i]=='')
i++;
while(line[i]!
='')
colum[j++]=line[i++];
colum[j]='\0';
i=atoi(colum);
fclose(pf);
returni;
}
fclose(pf);
return-1;
}
/*
*信号灯上的down/up操作
*semid:
信号灯数组标识符
*semnum:
信号灯数组下标
*buf:
操作信号灯的结构
*/
intdown(intsem_id){
structsembufbuf;
buf.sem_op=-1;
buf.sem_num=0;
buf.sem_flg=SEM_UNDO;
if((semop(sem_id,&buf,1))<0){
perror("downerror");
exit(EXIT_FAILURE);
}
returnEXIT_SUCCESS;
}
intup(intsem_id){
structsembufbuf;
buf.sem_op=1;
buf.sem_num=0;
buf.sem_flg=SEM_UNDO;
if((semop(sem_id,&buf,1))<0){
perror("uperror");
exit(EXIT_FAILURE);
}
returnEXIT_SUCCESS;
}
/*
*set_sem
函数建立一个具有
n
个信号灯的信号量
*
如果建立成功,返回
一个信号灯数组的标识符
sem_id
*
输入参数:
*sem_key
信号灯数组的键值
*sem_val
信号灯数组中信号灯的个数
*sem_flag
信号等数组的存取权限
*/
intset_sem(key_tsem_key,intsem_val,intsem_flg){
intsem_id;
Sem_unssem_arg;
if((sem_id=get_ipc_id("/proc/sysvipc/sem",sem_key))<0){
if((sem_id=semget(sem_key,1,sem_flg))<0){
perror("semaphorecreateerror");
exit(EXIT_FAILURE);
}
//设置信号灯的初值
sem_arg.val=sem_val;
if(semctl(sem_id,0,SETVAL,sem_arg)<0){
perror("semaphoreseterror");
exit(EXIT_FAILURE);
}
}
returnsem_id;
}
/*
*set_shm
函数建立一个具有
n
个字节
的共享内存区
*
如
果建立成功,返回
一个指向该内存区首地址的指针
shm_buf
*
输入参数:
*shm_key
共享内存的键值
*shm_val
共享内存字节的长度
*shm_flag
共享内存的存取权限
*/
char*set_shm(key_tshm_key,intshm_num,intshm_flg){
inti,shm_id;
char*shm_buf;
if((shm_id=get_ipc_id("/proc/sysvipc/shm",shm_key))<0){
if((shm_id=shmget(shm_key,shm_num,shm_flg))<0){
perror("shareMemoryseterror");
exit(EXIT_FAILURE);
}
if((shm_buf=(char*)shmat(shm_id,0,0))<(char*)0){
perror("getshareMemoryerror");
exit(EXIT_FAILURE);
}
for(i=0;i shm_buf[i]=0; } if((shm_buf=(char*)shmat(shm_id,0,0))<(char*)0){ perror("getshareMemoryerror"); exit(EXIT_FAILURE); } returnshm_buf; } intset_msq(key_tmsq_key,intmsq_flg){ intmsq_id; if((msq_id=get_ipc_id("/proc/sysvipc/msg",msq_key))<0){ if((msq_id=msgget(msq_key,msq_flg))<0){ perror("messageQueueseterror"); exit(EXIT_FAILURE); } } returnmsq_id; } Cons: #include"ipc.h" intmain(intargc,char*argv[]){ sem_val=1; sem_val=0; buff_num=13; pput_num=4; sem_val=buff_num; buff_key[0]=104; pput_key[0]=105; buff_key[1]=106; pput_key[1]=107; prod_key=201; pmtx_key=202; cons_key=301; cmtx_key=302; shm_flg=IPC_CREAT|0644; sem_flg=IPC_CREAT|0644; prod_sem=set_sem(prod_key,sem_val,sem_flg); cons_sem=set_sem(cons_key,sem_val,sem_flg); cmtx_sem=set_sem(cmtx_key,sem_val,sem_flg); buff_ptr[0]=(int*)set_shm(buff_key[0],buff_num,shm_flg); pput_ptr[0]=(int*)set_shm(pput_key[0],pput_num,shm_flg); buff_ptr[1]=(int*)set_shm(buff_key[1],buff_num,shm_flg); pput_ptr[1]=(int*)set_shm(pput_key[1],pput_num,shm_flg); down(cons_sem); down(cmtx_sem); sleep(3); if(*pput_ptr[1]<4){ buff_ptr[1][*pput_ptr[1]]=getpid(); *pput_ptr[1]=*pput_ptr[1]+1; printf("%dpeoplecometothebarbershop\n",getpid()); sleep(3); printf("%dpeoplesitonthesofa\n",getpid()); } else{ if(*pput_ptr[0]<13){ buff_ptr[0][*pput_ptr[0]]=getpid(); *pput_ptr[0]=*pput_ptr[0]+1; printf("%dpeoplecometotheshop\n",getpid()); } else{ printf("theshopisfullthepeopleleave\n"); } } up(cmtx_sem); up(prod_sem); return1; } Bar: #include"ipc.h" intmain(intargc,char*argv[]){ intn=0; if(argv[1]! =NULL) n=atoi(argv[1]); buff_num=13; pput_num=4; buff_key[0]=104; pput_key[0]=105; buff_key[1]=106; pput_key[1]=107; prod_key=201; pmtx_key=202; cons_key=301; cmtx_key=302; sem_val=buff_num; sem_val=0; sem_val=1; intrate=1; sem_flg=IPC_CREAT|0644; shm_flg=IPC_CREAT|0644; buff_ptr[0]=(int*)set_shm(buff_key[0],buff_num,shm_flg); buff_ptr[1]=(int*)set_shm(buff_key[1],buff_num,shm_flg); pput_ptr[0]=(int*)set_shm(pput_key[0],pput_num,shm_flg); pput_ptr[1]=(int*)set_shm(pput_key[1],pput_num,shm_flg); prod_sem=set_sem(prod_key,sem_val,sem_flg); cons_sem=set_sem(cons_key,sem_val,sem_flg); pmtx_sem=set_sem(pmtx_key,sem_val,sem_flg); while (1){ down(prod_sem); down(pmtx_sem); intpid; inti; if(*pput_ptr[1]>0){ rate=0; pid=buff_ptr[1][0]; printf("------------------------------------\n"); printf("barber%dwaswakedupandstartworkingon%dpeople\n",getpid(),pid); for(i=0;i<*pput_ptr[1]-1;i++){ buff_ptr[1][i]=buff_ptr[1][i+1]; } if(*pput_ptr[0]>0){ buff_ptr[1][*pput_ptr[1]-1]=buff_ptr[0][0]; printf("people%dsitsonthesofa\n",buff_ptr[0][0]); for(i=0;i<*pput_ptr[0]-1;i++){ buff_ptr[0][i]=buff_ptr[0][i+1]; } *pput_ptr[0]=*pput_ptr[0]-1; } else{ *pput_ptr[1]=*pput_ptr[1]-1; } printf("people%dfinishsandpaytothebarber%d\n",pid,getpid()); printf("people%dfinishspayingandleavetheshop\n",pid); } else{ printf("barber%dissleeping\n",getpid()); } if(rate! =1){ rate=1; printf("barber%dstartssleeping\n",getpid()); printf("------------------------------------\n"); } sleep(3); up(pmtx_sem); up(cons_sem); } return1; } 实验结果: 理发师1 理发师2 理发师3 顾客进程1 顾客进程2 总结: 总结和分析示例实验和独立实验中观察到的调试和运行信息,说明您对与解决非对称性互斥操作的算法有哪些新的理解和认识? 为什么会出现进程饥饿现象? 本实验的饥饿现象是怎样表现的? 怎样解决并发进程间发生的饥饿现象? 您对于并发进程间使用消息传递解决进程通信问题有哪些新的理解和认识? 通过进程同步实验,我明白了进程互斥机制, (1)非对称性互斥是指并发进程有且仅有一个可以执行某一段代码(称为临界区),具体是那个进程进入临界区是有临界区之前的代码(称为进入区)决定的,当进入临界区的调度机制是非对称,即某些进程具有优先进入的权利称为非对称的,例如此时有一个理发师从沙发室叫走了一个顾客,需要一个顾客从等候室进入沙发室,此时恰巧新来了以顾客,此时顾客进程和理发师进程都想要进入临界区(修改或查询等候室顾客数目),但按照正常人的思维,肯定是理发师先访问临界区,修改等候室顾客数目,然后是新来顾客访问临界区,查询是否可以进入理发店。 (2)进程饥饿指当等待时间给进程推进和响应带来明显影响称为进程饥饿。 产生饥饿的主要原因是: 在一个动态系统中,对于每类系统资源,操作系统需要确定一个分配策略,当多个进程同时申请某类资源时,由分配策略确定资源分配给进程的次序。 有时资源分配策略可能是不公平的,即不能保证等待时间上界的存在。 在这种情况下,即使系统没有发生死锁,某些进程也可能会长时间等待.当等待时间给进程推进和响应带来明显影响时,称发生了进程饥饿,当饥饿到一定程度的进程所赋予的任务即使完成也不再具有实际意义时称该进程被饿死。 举个例子,当有多个进程需要打印文件时,如果系统分配打印机的策略是最短文件优先,那么长文件的打印任务将由于短文件的源源不断到来而被无限期推迟,导致最终的饥饿甚至饿死。 (3)本实验的饥饿现象可能发生的情况事当顾客数目较少的情况下某一理发师进程可能一直被阻塞,即其余理发师持续服务;还有一种情况就是由于调度不合理,理完发的顾客会以为没有理发师收钱一直阻塞在交钱收费队列上。 (4)解决进程饥饿现象的唯一方法是修改进入临界区进程选择机制,打破不公平调度机制,使得想进入临界区的进程可以在有限等待中进入临界区。 (5)linux系统中进程可以通过共享内存和消息传递机制通信,通过消息传递队列,具体实现是发送进程发送信息给内核,然后内核实现了转发功能,接受进程从内核那里接收到发送进程所发送的信息。 适合传递少量信息,不适合传递大量信息,大量信息适合用共享内存机制传递。 收获和体会: 1.实验过程中在编写代码的时候要仔细认真,定义变量的时候要看明白变量的作用范围。 2. 实验时实验的步骤要记清楚,这样在执行实验的时候不会出差错 3. 要善于将之前学过的知识用在后面的学习中,比如进程的创建这里就可以用到 4. 学会分析题意,转
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 山东大学 操作系统 实验 进程