您好,欢迎访问三七文档
当前位置:首页 > 电子/通信 > 综合/其它 > 南昌大学操作系统实验报告二编程模拟进程间的同步和互斥
1南昌大学实验报告---(2)编程模拟进程间的同步和互斥学生姓名:张皓然学号:5501215001专业班级:本硕151实验类型:□验证□综合■设计□创新实验日期:2017.5.5实验成绩:一、实验目的通过实验加强对进程同步和互斥的理解,并掌握进程(线程)的创建和调用方法。学会使用信号量解决资源共享问题。学生可以自己选择在Windows或Linux系统下编写。二、实验内容(一)以下为Linux系统下参考程序,请编译、运行并观察程序的输出,并分析实验结果,写出实验报告。#includestdio.h//标准输入输出头文件#includestdlib.h//standardlibrary标准库头文件#includeunistd.h//POSIX标准定义的unix类系统定义符号常量的头文件,包含了许多UNIX系统服务的函数原型,例如read函数、write函数和getpid函数。#includetime.h//time.h是C标准库头文件,主要是一些和时间相关的函数#includesys/types.h//基本系统数据类型#includesys/wait.h//declarationsforwaiting#includelinux/sem.h//Semaphoreoperationflags#defineNUM_PROCS5//5个子进程#defineSEM_ID250//信号量#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,则操作将暂时阻塞,直到信号的值变为0。*///写文件,写入的数值是当前进程的进程号file=fopen(file_path,w);//写文件,若成功则返回文件起始地址;否则置02if(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;i3;i++){update_file(sem_set_id,file_name,pid);for(j=0;j4000000;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;iNUM_PROCS;i++){//通过fork()函数创建子进程3child_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;iNUM_PROCS;i++){intchild_status;wait(&child_status);}printf(main:we'redone\n);fflush(stdout);return0;}4(二)生产者消费者问题生产者消费者问题描述了两个共享固定大小缓冲区的线程——即所谓的“生产者”和“消费者”——在实际运行时会发生的问题。生产者的主要作用是生成一定量的数据放到缓冲区中,然后重复此过程。与此同时,消费者也在缓冲区消耗这些数据。该问题的关键就是要保证生产者不会在缓冲区满时加入数据,消费者也不会在缓冲区中空时消耗数据。#includesys/mman.h#includesys/types.h#includelinux/sem.h//系统读写安全相关函数#includefcntl.h#includeunistd.h#includestdio.h//该头文件内包含了通过错误码来回报错误资讯的宏#includeerrno.h#includetime.h#defineMAXSEM5//声明三个信号灯IDintfullid;intemptyid;Start建立信号集并进行初始化操作是否成功创建子进程先将进程ID写入某文件然后输出父进程继续运行,回收僵尸进程End继续运行父进程并回收僵尸进程TureFalseFalseTure次数==55intmutxid;intmain(){/*在sembuf结构中,sem_num是相对应的信号量集中的某一个资源,所以其值是一个从0到相应的信号量集的资源总数(ipc_perm.sem_nsems)之间的整数。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_SHARED|MAP_ANONYMOUS,-1,0);get=(int*)mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);set=(int*)mmap(NULL,sizeof(int),PROT_READ|PROT_WRITE,MAP_SHARED|MAP_ANONYMOUS,-1,0);*sum=0;*get=0;*set=0;//创建信号量、生成信号灯fullid=semget(IPC_PRIVATE,1,IPC_CREAT|00666);emptyid=semget(IPC_PRIVATE,1,IPC_CREAT|00666);mutxid=semget(IPC_PRIVATE,1,IPC_CREAT|00666);//为信号灯赋值arg.val=0;if(semctl(fullid,0,SETVAL,arg)==-1)perror(semctlsetvalerror);arg.val=MAXSEM;if(semctl(emptyid,0,SETVAL,arg)==-1)perror(semctlsetvalerror);6arg.val=1;if(semctl(mutxid,0,SETVAL,arg)==-1)perror(setctlsetvalerror);//初始化P,V操作V.sem_num=0;V.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(i100){//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)++;//判断这次消费是否为最后一次消费7if(*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;}89要解决该问题
本文标题:南昌大学操作系统实验报告二编程模拟进程间的同步和互斥
链接地址:https://www.777doc.com/doc-5613846 .html