程序代码:#includestdio.h//定义头文件#includetime.h#includeunistd.h#includesys/ipc.h#includesys/shm.h#includesys/sem.h#definePRODUCER2//宏定义生产者个数,2个#defineCOSTOMER3//宏定义消费者个数,3个#defineWRITE_NUM6//宏定义写缓冲次数,6次#defineREAD_NUM4//宏定义读缓冲次数,4次#defineSEM_ALL_KEY1342#defineSEM_EMPTY0#defineSEM_FULL1#defineBUF_LENGTH(sizeof(structcontainer_buffer))//宏定义缓冲区大小#defineBUFFER_NUM3//宏定义缓冲区个数,3个#defineSHM_MODE0600//宏定义创建和访问标志//缓冲区结构(循环队列)structcontainer_buffer//定义共享缓冲区结构{charletter[BUFFER_NUM];inthead;inttail;intis_empty;//判断缓冲区是否为空的标志};//得到6以内的一个随机数,产生延迟时间intrandom_num(){intt;srand((unsigned)(getpid()+time(NULL)));t=rand()%6;returnt;}//P操作,获得使用权voidp(intsem_id,intsem_num){structsembufsem_buff;sem_buff.sem_num=sem_num;sem_buff.sem_op=-1;sem_buff.sem_flg=0;semop(sem_id,&sem_buff,1);}//得到一个随机字符,模拟产品名字charrandom_letter(){chara;srand((unsigned)(getpid()+time(NULL)));a=(char)((char)(rand()%15)+'!');returna;}//V操作,释放使用权voidv(intsem_id,intsem_num){structsembufsem_buff;sem_buff.sem_num=sem_num;sem_buff.sem_op=1;sem_buff.sem_flg=0;semop(sem_id,&sem_buff,1);}//主函数intmain(intargc,char*argv[]){intshm_id,sem_id;//定义共享内存段标识变量shm_id,定义信号量标识变量sem_idintnum_p=0,num_c=0,i,j;//定义生产者和消费者的个数变量,初始化为0structcontainer_buffer*shmptr;//指向缓冲区结构的指针charpn;//随机字符,代表产品time_tnow;//时间变量pid_tpid_p,pid_c;//进程pid变量printf(Mainprocessstarts.\n);sem_id=semget(SEM_ALL_KEY,2,IPC_CREAT|0660);//创建两个信号量,empty,fullsemctl(sem_id,SEM_EMPTY,SETVAL,BUFFER_NUM);//索引为SEM_EMPTY的信号量值为3semctl(sem_id,SEM_FULL,SETVAL,0);//索引为SEM_FULL的信号量值为0if((shm_id=shmget(IPC_PRIVATE,BUF_LENGTH,SHM_MODE))0)//申请一个共享主存段,大小为缓冲区大小{exit(1);//失败退出}if((shmptr=shmat(shm_id,0,0))==(void*)-1)//将共享段与进程相连{exit(1);//失败退出}shmptr-head=0;//初始化缓冲区shmptr-tail=0;shmptr-is_empty=1;while((num_p++)PRODUCER)//循环创建2个生产者{if((pid_p=fork())0)//创建一个进程{exit(1);//失败退出}//如果是子进程,开始创建生产者if(pid_p==0){if((shmptr=shmat(shm_id,0,0))==(void*)-1)//将共享段与本进程相连{exit(1);//失败退出}for(i=0;iWRITE_NUM;i++)//循环尝试在缓冲区内放入数据为WRITE_NUM次{p(sem_id,SEM_EMPTY);//p操作,申请使用权,p(empty)sleep(random_num());//随机等待一段时间shmptr-letter[shmptr-tail]=pn=random_letter();//在缓冲队列里面放入一个产品shmptr-tail=(shmptr-tail+1)%BUFFER_NUM;shmptr-is_empty=0;//更新缓冲区状态为满now=time(NULL);//取得系统时间printf(currenttime:%02d:%02d:%02d\t,localtime(&now)-tm_hour,localtime(&now)-tm_min,localtime(&now)-tm_sec);for(j=(shmptr-tail-1=shmptr-head)?(shmptr-tail-1):(shmptr-tail-1+BUFFER_NUM);!(shmptr-is_empty)&&j=shmptr-head;j--)//输出缓冲区状态{printf(%c,shmptr-letter[j%BUFFER_NUM]);}printf(\tProducer%dputsaproductnamedas'%c'.\n,num_p,pn);//输出动作序列fflush(stdout);//清除文件缓存区v(sem_id,SEM_FULL);//释放对文件的使用权,V(full)}shmdt(shmptr);//将共享段与进程之间解除链接exit(0);//子进程终止}}for(;num_cCOSTOMER;num_c++)//循环创建COSTOMER个生产者{if((pid_c=fork())0)//创建一个子进程{printf(Erroronfork.\n);exit(1);//失败退出}//如果是子进程,开始创建消费者if(pid_c==0){if((shmptr=shmat(shm_id,0,0))==(void*)-1)//将共享段与本进程相连{printf(Erroronshmat.\n);exit(1);//失败退出}for(i=0;iREAD_NUM;i++)//循环读READ_NUM次{p(sem_id,SEM_FULL);//p操作,p(full),实现同步sleep(random_num());//随机等待一段时间pn=shmptr-letter[shmptr-head];//得到读取的产品标示字符shmptr-head=(shmptr-head+1)%BUFFER_NUM;shmptr-is_empty=(shmptr-head==shmptr-tail);//更新缓冲区产品状态now=time(NULL);//得到系统时间printf(currenttime:%02d:%02d:%02d\t,localtime(&now)-tm_hour,localtime(&now)-tm_min,localtime(&now)-tm_sec);for(j=(shmptr-tail-1=shmptr-head)?(shmptr-tail-1):(shmptr-tail-1+BUFFER_NUM);!(shmptr-is_empty)&&j=shmptr-head;j--)//输出缓冲区状态{printf(%c,shmptr-letter[j%BUFFER_NUM]);}printf(\tConsumer%dgetsaproductnamedas'%c'.\n,num_c,pn);fflush(stdout);//清除文件缓存区v(sem_id,SEM_EMPTY);}shmdt(shmptr);//解除共享段与本进程的连接exit(0);}}//主控程序最后退出while(wait(0)!=-1);//等待子进程结束shmdt(shmptr);//接触父进程和共享段的连接shmctl(shm_id,IPC_RMID,0);//删除共享内存段semctl(sem_id,IPC_RMID,0);printf(Mainprocessends.\n);fflush(stdout);//清除文件缓存区exit(0);}生产者流程图:生产者线程开始资源信号量P操作互斥信号量P操作生产一个产品把产品送入缓冲区互斥信号量V操作资源信号量V操作等待队列中有消费者线程等待队列中有消费者线程线程自我阻塞添加到等待队列线程自我阻塞添加到等待队列未通过未通过通过通过唤醒对头的消费者线程唤醒对头的消费者线程生产者线程结束YYNN消费者流程图:消费者线程开始资源信号量P操作互斥信号量P操作从缓冲区取出一个产品消费一个产品互斥信号量V操作资源信号量V操作等待队列中有生产者线程等待队列中有生产者线程线程自我阻塞添加到等待队列线程自我阻塞添加到等待队列未通过未通过通过通过唤醒对头的生产者线程唤醒对头的生产者线程消费者线程结束YYNN主程序流程图:Main函数开始初始化公共数据区初始化信号量创建生产者进程成功?创建消费者进程成功?创建统计进程成功定时到退出YYYNNN运行结果如下: