操作系统报告.docx
- 文档编号:4165191
- 上传时间:2023-05-06
- 格式:DOCX
- 页数:19
- 大小:300.48KB
操作系统报告.docx
《操作系统报告.docx》由会员分享,可在线阅读,更多相关《操作系统报告.docx(19页珍藏版)》请在冰点文库上搜索。
操作系统报告
《操作系统程序设计》
实验报告
2014年1月2日
操作系统报告
1、设计目标
(1)掌握并能够灵活使用线程机制
(2)掌握并能够灵活使用同步互斥机制
(3)了解并能够较灵活地使用IO技术
问题描述:
1)完成N个生产者和M个消费者线程之间的并发控制,N、M不低于30,数据发送和接收缓冲区尺寸不小于20个(每个产品占据一个)。
2)生产者线程1、3、5、7、9生产的产品供所有奇数编号的消费者线程消费,只有所有奇数编号的消费者线程都消费后,该产品才能从缓冲区中撤销。
3)其中生产者线程2、4、6、8、10生产的产品所有偶数编号的消费者线程都可消费,任一偶数编号消费者线程消费该消息后,该产品都可从缓冲区中撤销。
4)11-20号生产者线程生产的产品仅供对应编号的消费者线程消费。
5)编号生产者线程生产的产品可由任意的消费者线程消费。
6)每个生产线程生产30个消息后结束运行。
如果一个消费者线程没有对应的生产者线程在运行后,也结束运行。
所有生产者都停止生产后,如果消费者线程已经没有可供消费的产品,则也退出运行。
二、背景知识
原理
我们是利用多线程的并发执行,为了防止各个线程对于临界资源的抢占造成数据的修改照成数据的不一致,所以采取了互斥锁和信号量方面的操作,保证在临界资源的利用上,在一个同一个时间点只有一个线程对其进行修改,从而保证了数据的一致性和预防死锁的发生。
相关函数说明
在linux下,各个关于线程操作的系统调用函数一般位于#include
因此我们在这个程序中因此引入了#include
关于线程的操作,能用到的函数有:
1)pthread_create(pthread_t*thread,constpthread_attr_t*attr,void*(*start_routine)(void*),void*arg);
参数
第一个参数为指向线程标识符的指针。
第二个参数用来设置线程属性。
第三个参数是线程运行函数的起始地址。
最后一个参数是运行函数的参数。
若线程创建成功,则返回0。
若线程创建失败,则返回出错编号,并且*thread中的内容是未定义的。
2)intpthread_join(pthread_tthread,void**retval);
参数:
thread:
线程标识符,即线程ID,标识唯一线程。
retval:
用户定义的指针,用来存储被等待线程的返回值。
描述:
pthread_join()函数,以阻塞的方式等待thread指定的线程结束。
当函数返回时,被等待线程的资源被收回。
如果进程已经结束,那么该函数会立即返回。
并且thread指定的线程必须是joinable的。
返回值:
0代表成功。
失败,返回的则是错误号。
3)intpthread_mutex_lock(pthread_mutex_t*mutex);
参数:
mutex:
互斥锁变量,由pthread_mutex_t创建。
描述:
当pthread_mutex_lock()返回时,该互斥锁已被锁定。
线程调用该函数让互斥锁上锁,如果该互斥锁已被另一个线程锁定和拥有,则调用该线程将阻塞,直到该互斥锁变为可用为止。
返回值:
在成功完成之后会返回零。
其他任何返回值都表示出现了错误。
4)intpthread_mutex_unlock(pthread_mutex_t*mptr);
参数:
mptr:
互斥锁变量,由pthread_mutex_t创建。
描述:
作用和pthread_mutex_lock相反,是为了解锁一个锁的变量。
5)intpthread_mutex_trylock(pthread_mutex_t*mutex);
参数:
mutex:
是一个锁的对象变量名。
描述:
函数是pthread_mutex_lock函数的非阻塞版本。
如果mutex参数所指定的互斥锁已经被锁定的话,调用pthread_mutex_trylock函数不会阻塞当前线程,而是立即返回一个值来描述互斥锁的状况。
返回值:
函数成功返回0。
任何其他返回值都表示错误。
三、设计
设计环境
系统平台:
Unbuntu12.04
实现语言:
C语言
开发工具:
vim编辑器、gcc编译器。
概要设计
本程序中主要设计了两个功能函数producer(void*)和consumer(void*),来完成生产者生产了产品向缓冲区里面放,和完成消费者消费的时候在缓冲区里面取出产品。
运用在主函数里面创建的生产者和消费者线程,去调用他们性对应的功能函数,完成产品的生产和消费。
在完成各自的任务后,线程自动销毁。
其中程序的流程图为:
详细设计和实现思路实现
1)因为生产者和消费者都是各自运行的线程,在运行方面都不相互约束,但是在操控临界区的资源是会出现争夺的现象,故应该建立互斥锁和信号量的机制在合适的时候对各个线程进行加锁和解锁,以帮助程序能顺利的执行。
而且不仅要协调好生产线程和消费线程之间的关系,而且要协调各自功能线程对于临界资源的使用。
2)在产生的产品方面,我定义一个结构体,来表示一个产品,并给他赋予编号等相关属性。
3)在缓存区方面,同样采取了定义结果体,并申请了一个最大量为20的数组来作为一个缓冲池来缓存数据。
4)算法
A.主程序部分
a)创建生产者和消费者变量,并初始化变量。
b)生产者执行producer(),消费者执行consumer()
c)等待所有的进程结束。
d)主程序结束
B.生产者程序部分
a)生产者获得锁,并生产产品
b)将产品放入缓冲区
C.消费者程序部分
a)消费者获得锁
b)遍历缓冲区有没有自己能消费的产品,若有则消费,没有则等待
c)将消费的产品在缓冲区拿走。
生产者线程函数流程图为:
消费者进程函数的流程为:
四、测试
测试数据文件格式
对于程序的执行结果,通过截图的方式进行展示。
下图就是程序的执行的结果:
其中的显示就是关于程序的运行结果。
运行结果分析
经过对于运行结果的分析,我们发现其结果满足要求。
5、总结
经过本次的的课程设计,我们确实是收益匪浅。
其中我们学到了许多的东西,对于系统函数的调用和关于线程的控制。
尤其是关于线程的调度问题。
还有就是加锁的机制。
在做课程设计的过程中确实是遇到了不少的问题,有些问题确实是很难。
通过在网络上进行问题的查询,也得到了课堂上无法学到的知识。
网络上的各个论坛是我们进行学习的好地方。
里面大牛的讲解也确实是简单易懂。
自己也学会了在linux环境下的编程和编译,为以后linux下的编程打下了基础。
总之,这次的课程设计让自己受益匪浅。
六、参考代码
#include
#include
#include
#defineMAXSIZE20//缓冲区的数量
typedefstructmsg//产品结构
{
intp_no;
inttid;//生产者ID
intcounter;
intnum;
}Msg;
typedefstructmsg_buff//缓冲区的结构
{
intmsg_counter;
intp_no;
Msg*head;
}Msg_Buff;
Msg_Buffmsg_buff[MAXSIZE];//缓冲区
voidinit_msg_buff()//初始化缓冲区数组
{
inti;
for(i=0;i { msg_buff[i].head=NULL; msg_buff[i].msg_counter=0; msg_buff[i].p_no=0; } } pthread_mutex_tlock[MAXSIZE]; voidinit_lock() { //初始化缓冲区互斥锁 inti; for(i=0;i pthread_mutex_init(&lock[i],NULL); } voidadd(Msg_Buff*mbp,Msg*production,intp_no) { //向缓冲区增加产品 mbp->head=production; mbp->msg_counter=1; mbp->p_no=p_no; } voiddelete(Msg_Buff*mbp) { //把产品在缓冲区删除 Msg*production; production=mbp->head; mbp->head=NULL; mbp->msg_counter=0; mbp->p_no=0; free(production); } intvisit[MAXSIZE][15]; voidinit_visit(inti) { intj; for(j=0;j<31/2;j++) visit[i][j]=0; } intodd_visit(intbuffer,intp_no) { //消费者访问缓冲区 if(visit[buffer][p_no/2]==1) return2; visit[buffer][p_no/2]=1; inti,sum_visit=0; for(i=0;i<31/2;i++) sum_visit+=visit[buffer][i]; if(sum_visit==31/2) return1; return0; } voidconsumer(void*p) { //消费者消费函数 intp_no=(int)(p); inti=0,j=0; do { for(j=j%MAXSIZE;0! =pthread_mutex_trylock(&lock[j]);j=++j%MAXSIZE) ; if(msg_buff[j].msg_counter! =0) { if(p_no%2==0)//偶数消费者 { if(p_no>=11&&p_no<=20) { //当产品的编号在11-20之间的时候 if(msg_buff[j].p_no>20||msg_buff[j].p_no==p_no) { printf("消费者线程%d消费了生产者%d生产的产品\n",p_no,msg_buff[j].p_no); delete(&msg_buff[j]); } elseif((msg_buff[j].p_no<=10)&&(msg_buff[j].p_no%2==0)) { printf("消费者线程%d消费了生产者%d生产的产品\n",p_no,msg_buff[j].p_no); delete(&msg_buff[j]); } } else { if(msg_buff[j].p_no>20&&msg_buff[j].p_no<=30) { //生产者的编号在20-30之间的时候 printf("消费者线程%d消费了生产者%d生产的产品\n",p_no,msg_buff[j].p_no); delete(&msg_buff[j]); } elseif(msg_buff[j].p_no<=10&&msg_buff[j].p_no%2==0) { printf("消费者线程%d消费了生产者%d生产的产品\n",p_no,msg_buff[j].p_no); delete(&msg_buff[j]); } } } else//奇数消费者 { if(p_no>=11&&p_no<=20) { //当生产该产品的线程编号在11-20之间的时候 if(msg_buff[j].p_no>20||msg_buff[j].p_no==p_no) { printf("消费者线程%d消费了生产者%d生产的产品\n",p_no,msg_buff[j].p_no); delete(&msg_buff[j]); } elseif(msg_buff[j].p_no<=10&&msg_buff[j].p_no%2==1) { //当生产该产品的线程编号在1-10之间的时候 intkey=odd_visit(j,p_no); switch(key) { case2: break; case1: printf("消费者线程%d消费了生产者%d生产的产品\n",p_no,msg_buff[j].p_no); delete(&msg_buff[j]); init_visit(j); break; case0: printf("消费者线程%d消费了生产者%d生产的产品\n",p_no,msg_buff[j].p_no); } } } else { if(msg_buff[j].p_no>20&&msg_buff[j].p_no<=30) { //当生产该产品的线程编号在20-30之间的时候 printf("消费者线程%d消费了生产者%d生产的产品\n",p_no,msg_buff[j].p_no); delete(&msg_buff[j]); } elseif(msg_buff[j].p_no<=10&&msg_buff[j].p_no%2==1) { intkey=odd_visit(j,p_no); switch(key) { case2: break; case1: printf("消费者线程%d消费了生产者%d生产的产品\n",p_no,msg_buff[j].p_no); delete(&msg_buff[j]);//删除一个节点,表示该产品被消费了 init_visit(j); break; case0: printf("消费者线程%d消费了生产者%d生产的产品\n",p_no,msg_buff[j].p_no); } } } } } pthread_mutex_unlock(&lock[j++]); usleep(rand()%MAXSIZE); } while (1); printf("消费者线程%d自己销毁了! \n",p_no); } voidproducer(void*p)//生产者进程 { intp_no=(int)(p); inti=0,j=0,k=0; for(i=0;i<30;i++)//生产30个消息 { for(j=j%MAXSIZE;0! =pthread_mutex_trylock(&lock[j]);j=++j%MAXSIZE) ; if(msg_buff[j].msg_counter==0) { Msg*production; production=malloc(sizeof(Msg)); production->p_no=p_no; production->num=rand()%1000; init_visit(j); add(&msg_buff[j],production,p_no); printf("生产者%d生产了一个产品放在了%d缓冲区\n",p_no,j); } else --i; pthread_mutex_unlock(&lock[j++]); } printf("生产者线程%d已经生产了30个产品\n",p_no); } voidinit()//整体初始化 { inti; for(i=0;i<30;i++) init_visit(i); init_lock(); init_msg_buff(); } intmain(intargc,char*argv[]) { pthread_tp_pth[30],c_pth[30]; inti=0; srand(time(NULL)); init();//初始化 for(i=0;i<30;i++) pthread_create(&c_pth[i],NULL,(void*)consumer,(int*)(i+1)); for(i=0;i<30;i++) pthread_create(&p_pth[i],NULL,(void*)producer,(int*)(i+1)); for(i=0;i<30;i++) pthread_join(p_pth[i],NULL); return0; }
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 操作系统 报告