版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
㊂南昌大学实验报告——(2)编程模拟进程间的同步和互斥学生姓名: 张皓然学号:5501215001 专业班级:本硕151实验类型:口验证□综合■设计口创新实验日期:2017.5。5实验成绩:—一、 实验目的通过实验加强对进程同步和互斥的理解,并掌握进程(线程)的创建和调用方法。学会使用信号量解决资源共享问题。学生可以自己选择在Windows或Linux系统下编写。二、 实验内容以下为Linux系统下参考程序,请编译、运行并观察程序的输出,并分析实验结果,写出实验报告。#include<stdio.h>//标准输入输出头文件#include〈stdlib.h>//standardlibrary标准库头文件#include<unistd。h>//POSIX标准定义的unix类系统定义符号常量的头文件,包含了许多UNIX系统服务的函数原型,例如read函数、write函数和getpid函数。#include<time.h>//time。h是C标准库头文件,主要是一些和时间相关的函数include〈sys/types。h>//基本系统数据类型#include〈sys/wait.h〉//declarationsforwaiting#include〈linux/sem。h〉//Semaphoreoperationflags#defineNUM_PROCS5//5个子进程defineSEM_ID 250//信号量defineFILE_NAME”/tmp/sem_aaa”#defineDELAY4000000voidupdate_file(intsem_set_id,char大file_path,intnumber)(structsembufsem_op;FILE*file;//建立一个文件指针//等待信号量的数值变为非负数,此处设为负值,相当于对信号量进行P操作sem_op。sem_num=0;sem_op.sem_op=—1;sem_op。sem_flg=0;semop(sem_set_id,&sem_op,1);/大操作一组信号,进程的标识符号为sem_set_id,sem_op是结构指针。sem_op:如果其值为正数,该值会加到现有的信号内含值中,通常用于释放所控资源的使用权;如果sem_op的值为负数,而其绝对值又大于信号的现值,操作将会阻塞,直到信号值大于或等于sem_op的绝对值,通常用于获取资源的使用权;如果sem_op的值为0,贝9操作将暂时阻塞,直到信号的值变为0。*/〃写文件,写入的数值是当前进程的进程号file=fopen(file_path,"w”);〃写文件,若成功则返回文件起始地址;否则置0if(file){//临界区fprintf(file,”%d\n",number);//将进程号写入大file处printf("%d\n”,number);将当前的进程号输到标准输出里。fclose(file);//关闭文件}〃发送信号,把信号量的数值加1,此处相当于对信号量进行V操作sem_op.sem_num=0;sem_op。sem_op=1;sem_op.sem_flg=0;semop(sem_set_id,&sem_op,1);}//子进程写文件voiddo_child_loop(intsem_set_id,char大file_name){pid_tpid=getpid();inti,j;//取得目前进程的识别码,返回当前的进程的标识符for(i=0;i〈3;i++){update_file(sem_set_id,file_name,pid);for(j=0;j<4000000;j++);}}intmain(intargc,char*大argv){intsem_set_id; //信号量集的IDunionsemunsem_val;//信号量的数值,用于semctl()intchild_pid;inti;intrc;//建立信号量集,ID是250,其中只有一个信号量sem_set_id=semget(SEM_ID,1,IPC_CREAT|0600);if(sem_set_id==—1){/偌调用失败,输出错误类型,强制退出程序perror("main:semget");exit(1);}//把第一个信号量的数值设置为1sem_val。val=1;rc=semctl(sem_set_id,0,SETVAL,sem_val);if(rc==-1){〃测试是否成功调用semclt()函数perror("main:semctl”);exit(1);}//建立一些子进程,使它们可以同时以竞争的方式访问信号量for(i=0;i〈NUM_PROCS;i++){//通过fork()函数创建子进程
child_pid=fork();switch(child_pid)(case-1:perror(”fork");case0: //子进程写文件do_child_loop(sem_set_id,FILE_NAME);exit(0);default://父进程接着运行break;}}//等待子进程结束for(i=0;i〈NUM_PROCS;i++){intchild_status;wait(&child_status);}redone\n)zhainghaorari@zhaAgha&rari-vtrtual-nachtrie>-$cd桌面zhamglhaorar@zhaAgha&ran-vtrtiidl-nachtfte:~/^iSi$dtrhalop.cp.c-viware-t&ols-redone\n)zhainghaorari@zhaAgha&rari-vtrtual-nachtrie>-$cd桌面zhamglhaorar@zhaAgha&ran-vtrtiidl-nachtfte:~/^iSi$dtrhalop.cp.c-viware-t&ols-dtstrtb无标题文档~zhangtiaardngzhdngtiaoran-virtual-machine: ®$gcczhangliaoran@zhangtiaoran-virtual-nachine^/^ns-/p49484946494749454944494749444949494549464947494S■4940■49454944pialn:we!redonezhanghaoran@zhanghaoran-vtrtual-nachtne:-/\5|®$|printf('main:fflush(stdout);return0;}(二)生产者消费者问题生产者消费者问题描述了两个共享固定大小缓冲区的线程一一即所谓的“生产者”和“消费者”-一在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。#include<sys/mman。h〉#include〈sys/types.h〉#include<linux/sem。h〉〃系统读写安全相关函数#include〈fcntl.h〉#include〈unistd。h>#include<stdio。h〉〃该头文件内包含了通过错误码来回报错误资讯的宏#include〈errno。h>#include〈time.h〉#defineMAXSEM5〃声明三个信号灯IDintfullid;intemptyid;intmutxid;intmain(){/大在sembuf结构中,sem_num是相对应的信号量集中的某一个资源,所以其值是一个从0到相应的信号量集的资源总数(ipc_perm.sem_nsems)N间的整数。sem_op指明所要执行的操作,sem_flg说明函数semop的行为.sem_op的值是一个整数。释放相应的资源数,将sem_op的值加到信号量的值上。*/structsembufP,V;unionsemunarg;〃声明共享主存int*array;int大sum;int大set;int大get;〃映射共享主存/大mmap是一种内存映射文件的方法,即将一个文件或者其它对象映射到进程的地址空间实现文件磁盘地址和进程虚拟地址空间中一段虚拟地址的一一对映关系。实现这样的映射关系后,进程就可以采用指针的方式读写操作这一段内存而系统会自动回写脏页面到对应的文件磁盘上即完成了对文件的操作而不必再调用read,write等系统调用函数。相反,内核空间对这段区域的修改也直接反映用户空间从而可以实现不同进程间的文件共享。*/array=(int*)mmap(NULL,sizeof(int)*MAXSEM,PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS—1,0);sum=(int*)mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHAREDIMAP_ANONYMOUS,-1,0);get=(int大)mmap(NULL,sizeof(int),PROT_READIPROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);set=(int*)mmap(NULL,sizeof(int),PROT_READIPROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);*sum=0;*get=0;大set=0;〃创建信号量、生成信号灯fullid=semget(IPC_PRIVATE,1,IPC_CREATI00666);emptyid=semget(IPC_PRIVATE,1,IPC_CREATI00666);mutxid=semget(IPC_PRIVATE,1,IPC_CREATI00666);〃为信号灯赋值arg.val=0;if(semctl(fullid,0,SETVAL,arg)==—1)perror("semctlsetvalerror");arg.val=MAXSEM;if(semctl(emptyid,0,SETVAL,arg)==-1)perror("semctlsetvalerror");argoval=1;if(semctl(mutxid,0,SETVAL,arg)==—1)perror("setctlsetvalerror”);//初始化P,V操作V.sem_num=0V.sem_op=1;V。sem_flg=SEM_UNDO;P.sem_num=0;P.sem_op=—1;P。sem_flg=SEM_UNDO;//生产者进程if(fork()==0) {inti=0;while(i<100){//semop(信号量,资源,数目)semop(emptyid,&P,1);//mutex实现临界资源的互斥使用semop(mutxid,&P,1);array[大(set)%MAXSEM]=i+1;printf("Producer%d\n",array[(*set)%MAXSEM]);〃生产产品的标号+1(*set)++;semop(mutxid,&V,1);semop(fullid,&V,1);i++;}sleep(10);printf(''Producerisover”);exit(0);}else(//ConsumerA进程if(fork()==0){while(1){semop(fullid, &P,1);semop(mutxid,&P,1);//判断是否所有产品都被消费了if(大get==100)break;*sum+=array[(大get)%MAXSEM];printf("TheComsumerAGetNumber%d\n",array[(*get)%MAXSEM]);(*get)++;//判断这次消费是否为最后一次消费if(大get==100)printf("Thesumis%d\n",*sum);semop(mutxid,&V,1);semop(emptyid,&V,1);sleep(1);}printf("ConsumerAisover");exit(0);}else{//ConsumerB进程if(fork()==0){while(1)(semop(fullid, &P,1);semop(mutxid,&P,1);if(大get==100)break;*sum+=array[(*get)%MAXSEM];printf("TheComsumerBGetNumber%d\n",array[(*get)%MAXSEM]);(大get)++;if(大get==100)printf(”Thesumis%d\n", 大sum);semop(mutxid,&V,1);semop(emptyid,&V,1);sleep(1);}printf(''ConsumerBisover”);exit(0);}}}//sleep(20);return0;}
立件[日编罪[f】at(v)揪室缶J建果E苹瞄(研二凰二导S三三Number1GetNumber2GetGetGetNumber3Number4TheConsumerBGetNumber5TheconsuFierAGetNumber6Producer13M\—LiAtfeF3''' ■.」一u-1?立件[日编罪[f】at(v)揪室缶J建果E苹瞄(研二凰二导S三三Number1GetNumber2GetGetGetNumber3Number4TheConsumerBGetNumber5TheconsuFierAGetNumber6Producer13M\—LiAtfeF3''' ■.」一u-1?■二’-D”r--0.SD/-19J1 D.dOxO.DQ R 1/1NunberGetNunberGetGetNunber54NumberGetNunberGet56NumberGet57NunberGet58GetNunberNumberGetNunberGetNumberGetc连按已断开-怒现在处于商城状态网塔sdemote:1&6:4:warning:incanpatibleimplicitdeclarationofbuilt-infunction1esitR[enabledbydefault]exttfe);=tjzhanghsorangzIiainighaDran-virtu.3l-niciclhine;-/^0i$^/denozhanghaorangzhanghaorari-virtuaL-macIhine:-/桌面5Producer1TheConsunerBProducer2TheConsumerAProducer3Producer4Producer5Producer6Producer7TheConsunerBTheconsumerAProducerSProducer9=tji:i-0.50/-19.S1£J灯片1/1Thecom&umerBProducer57Thecon&unerAProducer58TheConsumersProducerS9TheComsumerAProducer60TheConsumerBProducer61Thecom&umerAProducer62Thecon&unerBProducer61TheComsumerAProducer54TheComsumerBi:i-0.50/-19.S1£J灯片1/1
要解决该问题,就必须让生产者在缓冲区满时休眠(要么干脆就放弃数据),等到下次消费者消耗缓冲区中的数据的时候,生产者才能被唤醒,开始往缓冲区添加数据.同样,也可以让消费者在缓冲区空时进入休眠,等到生产者往缓冲区添加数据之后,再唤醒消费者.通常采用进程间通信的方法解决该问题,常用的方法有信号灯法等.如果解决方法不够完善,则容易出现死锁的情况。出现死锁时,两个线程都会陷入休眠,等待对方唤醒自己。该问题也能被推广到多个生产者和消费者的情形。思考:1、 关于sleep()Sleep函数对于指定的时间间隔挂起当前的执行线程.格式:VOIDSleep(DWORDdwMilliseconds);dwMilliseconds:定义挂起执行线程的时间,以毫秒(ms)为单位。取值为0时,该线程将余下的时间片交给处于就绪状态的同一优先级的其他线程。若没有处于就绪状态的同一优先级的其他线程,则函数立即返回,该线程继续执行。若取值为INFINITE则造成无限延迟。2。 关于semop在Linux下,PV操作通过调用semop函数来实现。该函数定义在头文件sys/sem.h中,原型如下:intsemop(intsemid,structsembuf*sops,size_tnsops);流程图:
0(三)第三个程序没有调试好0(E]讶春〔仍博索财蜷ssm牌卧Mzhanghaonan便thunghgran,v\rtual-mdchint(E]讶春〔仍博索财蜷ssm牌卧M[irtntfC"CustomerKd:IamgettingtnItnel\n"t(tnt*)num):A.p.c:114;:5:warning:formatf56d*expectsargumentoftype1tntpbutargument2h非typeJLot*p[-Wformat=]prtntf("Customer%d:wh-atever.++I
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2024商标转让合同模板
- 2024医疗设备投放合作协议书
- 2024年企业合并合同协议书
- 2024年度金融服务合同:R银行企业贷款与金融服务
- 2024年专业培训学校业务合作合同版B版
- 2024年商场运维管理及维护合同版B版
- 佳木斯大学《税务会计》2021-2022学年第一学期期末试卷
- 2024年兼职工作劳务协议范例版B版
- 佳木斯大学《管理运筹学》2021-2022学年第一学期期末试卷
- 2024年土地二次租赁协议范例版
- 口腔修复:桩核冠课件
- 发现你的优势课件
- 小学科学六年级上册《铁钉生锈了》课件
- 会说话的百分数-课件完整版
- TCAEC 003-2021 化工建设工程监理规程
- (新版)中国联通政企智慧运营考试题库(含答案)
- 洗红领巾(课堂)课件
- 评剧《秦香莲》剧本
- 九年级上期中家长会(共35张)课件
- 建筑隔震支座安装说明课件
- 实验室定置化管理标准
评论
0/150
提交评论