操作系统-pv操作
《现代操作系统》课程设计
课程设计报告(论文)
报告(论文)题目: PV操作解决生产者-消费者问题 作者所在系部: 计算机科学与工程系 作者所在专业: 网络工程 作者所在班级: ******* 作 者 姓 名 : ****** 作 者 学 号 : ************ 指导教师姓名: ******* 完 成 时 间 : 2009年11月10日
*******************
第 1 页 共 20 页
《现代操作系统》课程设计
............................................................................................................................................ 3
.............................................................................................................................. 4 1.1 ..................................................................................................................................... 4 1.2 ............................................................................................................................. 4 1.3 ............................................................................................................................. 4 1.4 ............................................................................................................................. 4 1.5 ............................................................................................................................. 4 1.6 ............................................................................................................................. 5
........................................................................................................... 5 2.1 ............................................................................................................................. 5
2.1.1 PV操作原理 ................................................................................................................................ 5
2.1.2生产者消费者问题描述 .............................................................................................................. 5
2.1.3 程序
图 ................................................................................................................................. 7
2.1.4 调试工具与命令 ......................................................................................................................... 8
2.1.5关键代码
.............................................................................................................................. 8
........................................................................................................... 9 3.1 .......................................................................................................................... 9 3.2 ....................................................................................................................... 9 3.3 ............................................................................................................................ 10
3.3.1有PV控制运行结果 ................................................................................................................. 10
3.3.2无PV控制运行结果 ................................................................................................................. 10 3.4 ......................................................................................................................... 11
3.4.1有PV控制进程结束 ................................................................................................................. 11
3.4.2无PV控制进程结束 ................................................................................................................. 11
............................................................................................................................ 12
.................................................................................................................................. 13
................................................................................................................... 14
第 2 页 共 20 页
《现代操作系统》课程设计
进程同步机制的主要任务是对多个机关进程在执行次序上进行协调,使并发执行的诸
进程之间能按照一定的
(或时序)共享系统资源,并能很好的相互合作,从而使程序
的执行具有再现性。
生产者和消费者是典型的进程同步问题,它
了进程同步与临界资源的关系。在生
产者-消费者问题中,所描述的是生产者生产和消费者消费之间的关系。为使生产者进程与
消费者进程并发执行,在两者之间设置了一个具有n个缓冲区的缓冲池。生产者进程将它所生产的产品,按序放入一个缓冲区中。消费者进程也按序从一个缓冲区中取走产品去消
费。尽管所有的生产者进程和消费者进程,都是以异步方式运行的,但他们之间必须保持
同步关系,即不允许消费者进程到一个空缓冲区中取产品,也不允许生产者进程向一个已
装满产品且尚未取走的缓冲区中投放产品。
一般来说,信号量S>=0时,S表示可用资源的数量。执行一次P操作意味着请求分配
一个单位资源,因此S的值减1;当S<0时,表示已经没有可用资源,请求者必须等待别
的进程释放该类资源,它才能运行下去。而执行一个V操作意味着释放一个单位资源,因此S的值加1;若S<=0,表示有某些进程正在等待该资源,因此要唤醒一个等待状态的进
程,使之运行下去。多线程就是有两个或两个以上的信号量,线程同步的运行。
第 3 页 共 20 页
《现代操作系统》课程设计
1.1
操作系统是现代计算机系统中最基本和最重要的系统让软件,它是计算机科学与技术
专业的一门重要的基础课程。通过讲授本课程,学生可以全面的了解操作系统的概念,操
作系统是一组能有效的组织和管理计算机硬件和软件资源,合理地对各类资源进行调度,
以方便用户使用的程序的集合。其作用是管理好这些设备,提高利用率和系统的吞吐量,
为用户和应用程序提供简单的接口,便于用户使用。学完操作系统,可以更好的搭建学生
的专业基础知识。
本次课程设计在本着加强课本知识运用能力的前提下,我选取了用PV操作来解决生产者消费者问题这个题目。该题目主要是解决操作系统中进程的同步与互斥的问题。 1.2
图书馆五楼计算机系软二机房
1.3
在Linux下用C语言,调用Linux提供的系统函数编写程序,实现操作系统中生产着
与消费者的同步于互斥问题
1.4
结合操作系统理论课程中学习到的记录型信号量机制,进程的创建、调度、终结
,
在Linux操作系统下进行实际编程模拟操作,完成PV操作解决生产者-消费者问题,使进程能够在系统中有条不紊的运行,从而使大家对可以把理论知识运用到实践中来,加深对
理论的理解。
1.5
设计PV操作算法,用信号量机制实现生产者与消费者同步与互斥问题,并与无PV
情况下进行对比。定义20个缓冲区,将其初始化为0。调用随机函数rand()生成随机数,把随机数通过生产者放入缓冲区。若缓冲区满则其值非0。当消费者从缓冲区中去数后缓冲区值变为0。程序可显示缓冲区中的全部内容,方便观察生产者与消费者的行为。程序
可通过设置sleep(time)中time的值来控制生产者与消费者的执行顺序。
第 4 页 共 20 页
《现代操作系统》课程设计
1.6
Ubuntu 默认桌面环境采用 GNOME(The GNU Network Object Model Environment,GNU网络对象模型环境),一个 UNIX 和 Linux 主流桌面套件和开发平台。
2.1
2.1.1 PV
信号量机制是一种卓有成效的进程同步工具。在长期的广泛应用中,得到了很大的发
展,信号量机制已被广泛地应用于但处理机和多处理机系统中。
在记录型信号量中,s.value的初始值表示系统中某资源的数目,因而又成为资源信号
量。对它的每次p操作,意味着进程请求一个单位的该资源,使系统中可供分配的该类资
源减少一个,因此描述为s.value:=s.value-1;当s.value<0时,表示该类资源已分配完毕,
因此进程调用block原语,进行自我阻塞,放弃处理机,并插入到信号量链表S.L中。
对信号量的每次v操作,表示执行进程释放一个单元资源,使系统中可供分配的该类
资源数增加一个。故s.value:=s.value+1操作表示资源数目加1。若加1后仍是s.value<=0,则表示在该信号量链表中,仍有等待该资源的进程被阻塞,故还应调用wakeup原语,将S.L链表中的第一个等待进程唤醒。如果s.value的初始值为1,表示只允许一个进程访问
临界资源,此时信号量转化为互斥信号量用于进程互斥。
2.1.2
为了实现生产者与消费者同步与互斥的问题,该程序用记录型信号量机制来实现。
假定在生产者与消费者之间,利用一个公共的缓冲池来进行通信,生产者将所生产的
信息放入其中,消费者cognitive缓冲池中取得消息来消费,该缓冲池具有n个缓冲区,其编号为0,1,2,3???,n-1;设置一个互斥信号量mutex,用于实现诸进程对缓冲池的互斥
使用,其初值为1,利用资源信号量empty,表示缓冲池中空缓冲区的数目,其初值为n;full分别表示缓冲池中满缓冲区的数目,其初值为0.又假定这些生产者和消费者相互等效,
只要缓冲池未满,生产者便可将消息送入由指针in所指的缓冲区;只要缓冲池未空,消费
者变可以从由指针out所指示的缓冲区中,取走一个消息。对生产者消费者的问题可以描
述如下:
第 5 页 共 20 页
《现代操作系统》课程设计
Var metux,empty,full:semaphore=1,n,0;
Buffer:array[0,???n-1] of item; In,out:integer:=0;
Begin:
Pabegin
Producer:begin
Repeat
Producer an item nextp;
P(empty);
P(mutex);
buffer(in):=nextp;
in:=(in+1)mod n;
V(mutex);
V(full);
Until false;
End
Consumer:begin
Repeat
P(full);
P(mutex);
nextc:= buffer(out);
out:=(out+1)mod n;
V(mutex);
V(empty);
Until false;
End
Parend
End
第 6 页 共 20 页
《现代操作系统》课程设计 2.1.3
创建进程模拟生产者消费者
消 费 者 生 产 者
阻塞
N 有消费请求? 存在空缓冲区
阻塞 Y 阻塞
此请求可满足? 另一生产者正Y
在写?
N 确定产品位置
进入临界区 阻塞
此产品正被消费? 从空缓冲区中为本生产者分
配一个空间
进入临界区(对同一产品进行请
求的消费者之间互斥) 退出临界区
消费产品、并判断是否应该释放在该缓冲区中写入产品
产品所占缓冲区
通过信号量通知等待本产品
的消费者 退出临界区
结束消费者进程 结束生产者进程
图 2-1 程序流程图
第 7 页 共 20 页
《现代操作系统》课程设计
2.1.4
启动vi编辑器:vi [文件]
:q! 不存盘退出。
:w 将缓冲区内的资料写入磁盘中,但并不离开vi
:q 直接退出。
:wq 存盘并退出
:wq! 强行存盘退出(相当于ZZ)
编译命令:gcc -o 目标文件名 源文件名
执行命令:./ 目标文件名
2.1.5
1. 信号量操作
创建信号量函数 :int semget(key_t key, int nsems, int semflg);
控制信号量函数:int semctl(int semid, int semnum, int cmd, union semun arg);
PV操作函数: int semop(int semid, struct sembuf * sops, unsigned nsops);
信号量的使用是一个很容易出错的问题,如在程序退出时,必须还原所有的加锁,
否则程序会运行出错。本系统在缓冲区操作时分为两种情况sem_p(emptyid, 0)之后,
如果要写入的缓冲区为空,则执行写入操作然后sem_v (fullid, 0),如果要写入的缓
冲区为空,则执行程序不能写入换冲区,要执行还原操作,执行sem_v (emptyid, 0)
操作。
本程序定义的信号量有emptyid、fullid、mutexid。
fullid=semget(IPC_PRIVATE,1,IPC_CREAT|0666);
emptyid=semget(IPC_PRIVATE,1,IPC_CREAT|0666);
mutexid=semget(IPC_PRIVATE,1,IPC_CREAT|0666);
2. 共享内存操作
创建共享内存: shmget(char * pathname, int proj_id, size_t size);
arrayid=shmget(IPC_PRIVATE,sizeof(int)*MAXSHM,IPC_CREAT|0666);
getid=shmget(IPC_PRIVATE,sizeof(int),IPC_CREAT|0666);
setid=shmget(IPC_PRIVATE,sizeof(int),IPC_CREAT|0666);
删除共享内存: shmctl (char * viraddr, int shmid);
本程序定义的共享内存有array、set、get。其中array为20个共享缓冲区,set为多
个生产者进程共同的取数端和计数器,get为消费者的计数器。 3. 进程操作
第 8 页 共 20 页
《现代操作系统》课程设计
创建进程函数:fork();
进程退出函数:exit (0);
这进程等待子进程退出函数:wait (sumer[t], (int *)0, 0);
Main主进程使用fork()生成子进程,这样就生成里一个消费者或生产者进程,并且
还为主进程的子进程。当子程序执行了exit(0)
3.1
在Linux下编译源文件用命令gcc:如图3-1。
图 3-1 编辑命令gcc
3.2
在Linux先执行目标文件用命令./目标文件。如图3-2。
图 3-2 执行命令./目标文件
第 9 页 共 20 页
《现代操作系统》课程设计 3.3
3.3.1PV
有PV控制下的运行结果如图3-3所示
图3-3 有PV控制下的运行结果
3.3.2PV
无PV控制下的运行结果如图3-4所示
图3-4 无PV控制下的运行结果
第 10 页 共 20 页
《现代操作系统》课程设计 3.4
3.4.1PV
有PV控制下的进程结束显示结果如图3-5所示
图3-5有PV控制下的进程结束
3.4.2PV
无PV控制下的进程结束显示结果如图3-6所示
图 3-6无PV控制下进程的结束
第 11 页 共 20 页
《现代操作系统》课程设计
此次课程设计学习了在C语言里定义信号量、共享内存的使用、用fork()函数创建
子进程以及定义信号量的PV操作,并通过sleep函数来调整生产者和消费者对缓冲区的操作,在无PV时初始时让sleep(time)中的time=1可以看到消费者对缓冲区进行读,而此时生产者并无向缓冲区中放东西。在有PV控制下必须是缓冲区非空且无生产者对缓冲区进
行操作时消费者才能对缓冲区操作,同理只有缓冲区不满而且无消费者操作时生产者才能
对缓冲区操作。通过与无PV控制下对缓冲区进行读写可以进一步理解在信号量控制下的
作用。
这次试验让我深刻的了解了操作系统的PV操作,也加深了对操作系统的认识,课本上的概念也有了深入的印象,使我对操作系统这个学科有了整体观感,这次试验,使我受
益匪浅,感谢老师的指导和帮助,感谢同学的帮助和关心!
第 12 页 共 20 页
《现代操作系统》课程设计
[1] 汤小丹,梁红兵,哲凤屏,汤子瀛 著。现代操作系统。电子工业出版社,2008年
4月
[2] 汤小丹,梁红兵,哲凤屏,汤子瀛 编著。计算机操作系统。现电子科技大学出版
社,2007年5月
[3] 《计算机操作系统教程》清华大学出版社 张尧学
第 13 页 共 20 页
《现代操作系统》课程设计
#include
数据结构*/ #include union semun arg; #include /*定义共享内存*/
#include int shmid1,shmid2,shmid3; #include int *buffer,*get,*set; #include /*创建信号量并初始化*/
#include emptyid=semget(IPC_PRIVAT#include E,1,IPC_CREAT|0666); #define MAX 20 // 定义缓冲 fullid=semget(IPC_PRIVATE,1
区的大小 ,IPC_CREAT|0666);
/*定义信号量内部标识*/ mutexid=semget(IPC_PRIVATint emptyid; E,1,0666|IPC_CREAT); int fullid; arg.val=1; /*为信号量
int mutexid; 赋初值*/ int main() if(semctl(mutexid,0,SETVAL,a{ rg)==1)
printf("**********使用pv操 perror("semctl setval
作***********\n"); error");
pv(); arg.val=20; /*为信号量
printf("*************无pv操赋初值*/
作*********\n"); if(semctl(emptyid,0,SETVAL,a
no_PV(); rg)==1)
} perror("semctl setval int pv() error");
{ arg.val=0;
int i,C1,C2,p1,p2,m; if(semctl(fullid,0,SETVAL,arg)
srand(time(NULL)); ==1)
/*定义P、V操作所用的数据 perror("semctl setval
结构*/ error");
struct sembuf P,V; /*定义信号量的P操作*/
/*定义给信号量赋初值的参数 P.sem_num=0;
第 14 页 共 20 页
《现代操作系统》课程设计
P.sem_op=-1; semop(emptyid,&P,1);
P.sem_flg=0; //对emptyid执行P操作
/*定义信号量的V操作*/ semop(mutexid,&P,1);
V.sem_num=0; //对mutexid执行P操作
V.sem_op=1; if((*set)=20) ,4,0666|IPC_CREAT); break;
get=(int*)shmat(shmid3,0,0); }
(*get)=0; printf("P1 over!\n");
while((p1=fork())==-1); // exit(0); 创建生产者1子进程直到成功为止,p1存 } 放子进程的pid号 while((p2=fork())==-1); //
if(p1==0) 创建生产者2子进程直到成功为止,p1存
//返回值=0表示子进程返回 放子进程的pid号
{ if(p2==0) //返回值=0表
for(i=0;i=20) if((*get)>=MAX)
break; break;
} }
sleep(1); printf("C1 over!\n");
printf("P2 over!\n"); exit(0);
exit(0); }
} while((C2=fork())==-1); //创
while((C1=fork())==-1); //建消费者2子进程 创建消费者1子进程 if(C2==0)
if(C1==0) {
{ for(i=0;i=MAX) for( m=0;m=20)
printf("%d break; ",buffer[m]); }
printf("\n"); printf("P2 over!\n");
} exit(0);
(*set)++; }
if((*set)>=20) while((C1=fork())==-1); //
break; 创建消费者1子进程
} if(C1==0)
printf("P1 over!\n"); {
exit(0); for(i=0;i=MAX)
} break;
(*get)++; }
if((*get)>=MAX) printf("C2 over!\n");
break; exit(0);
} }
printf("C1 over!\n"); wait(0); //等待子进程终止
exit(0); wait(0);
} wait(0);
while((C2=fork())==-1); // shmdt(buffer); //断
创建消费者2子进程 开附接的共享内存
if(C2==0) shmdt(get); //断开附接的共
{ 享内存
for(i=0;i