设计一个程序,程序中有一个生产者进程两个消费者进程。生产者产生1~20的20个数。两个消费者从共享内存中取数。
首先分析题目
生产者和消费者之间存在着协同关系。而两个消费者要满足互斥。所以我们需要三个信号量,一个用来控制互斥,两个用来控制协同
我们知道前一种非常简单,实现互斥就是用一把公用的锁把临界区锁住
而协同关系则复杂一些。我们知道信号量的值就是进程可以使用的资源的个数。对于生产者来说,资源就是空的存储区。对于消费者来说,资源就是存有数据的存储区。所以用两个信号量,一个是empty,一个是full。empty初始值为1代表一开始内存是空闲的,full初始值为0表示没有数据可用。生产者在生产之前他会将empty变成0,然后生产之后他又把full变成1。empty避免了其他生产者在同一块内存上生产数据。而消费者在消费之前就把full变成0,消费之后又把empty变成1。这样两两协同,便实现了协同和互斥的关系。
接下来贴代码
包含头文件并定义所需全局变量:
#include <iostream>
#include <sys/types.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/mman.h>
#include <errno.h>
#include <time.h>
#include<unistd.h>
using namespace std;
struct sembuf P,V;
union senum{
int val;
struct semid_ds *buf;
unsigned short *array;
}arc;
封装函数:
void sem_init()//初始化信号量的运行环境
{
P.sem_num= 0;
P.sem_op =-1;//信号量在操作时-1
P.sem_flg=SEM_UNDO;
V.sem_num= 0;
V.sem_op =1;//信号量在操作时+1
V.sem_flg=SEM_UNDO;
cout<<"Semaphore Initiate Successfully"<<endl;
}
void v(int sem_id)//v操作
{
semop(sem_id,&V,1);
}
void p(int sem_id)//p操作
{
semop(sem_id,&P,1);
}
void sem_crea(int &sem_id,int val)//用val来给信号量赋初值
{
sem_id=semget(IPC_PRIVATE,1,IPC_CREAT|00666);
arc.val=val;
semctl(sem_id,0,SETVAL,arc);
}
主函数:
int main()
{
sem_init();
int mutx;
int full;
int empt;
char *shares;
int *num;
int shareid;
shareid=shmget(5,1280,0777|IPC_CREAT);//用同一个key可以得到同一块共享内存
shares=(char*)shmat(shareid,0,0);//得到共享内存的指针
sem_crea(mutx,1);
sem_crea(full,0);
sem_crea(empt,1);
num=(int *)shares;
pid_t p1;
pid_t p2;
p1=fork();//fork在子进程中返回0在父进程中返回子进程的pid_t
p2=fork();
if(p1==0)//生产者进程
{
int n=20;
while(n--)
{
p(empt);
*num=n;
v(full);
}
sleep(5);
exec(0);
}
else if(p2==0)//两个消费者进程
{
while(1)
{
p(full);
p(mutx);
cout<<"comsumer A :"<<*num<<endl;
v(mutx);
v(empt);
}
}
else
{
while(1)
{
p(full);
p(mutx);
cout<<"comsumer B :"<<*num<<endl;
v(mutx);
v(empt);
}
}
return 0;
}