本文主要分析的是多生产者,多消费者以及多个资源的进程间的同步和互斥机制。
操作系统中我们已经学习过了生产者和消费者之间的同步互斥模型
生产者:
{
生产一个产品;
p(empty);
p(mutex);
产品入buffer;
v(mutex);
v(full);
}
消费者
{
p(full);
p(mutex);
从buffer中取出产品;
v(mutex);
v(empty);
}
在真正编程实现是,采用IPC机制,因此要为生产者和消费者共同使用的变量创建共享内存区域并且将该共享内存区域映射到进程的地址空间中,从而可以直接对该地址空间
进行操作。
而且,在该模型中,使用了三个信号量,因此要采用linux中的信号量集机制。
#include <shm.h>
int main()
{
int num;
int shmid_goods,shmid_index,semid;
char* shmaddr=NULL;
int *indexaddr=NULL;
int is_noexist=0;
num=10;
//创建货物的共享内存区域,并且链接到进程用户空间。大小为10字节。
if((shmid_goods=createshm(".",'s',num))==-1)
{
if(errno==EEXIST)
{
if((shmid_goods=openshm(".",'s'))==-1)
{
exit(1);
}
}
else
{
perror("create shared memory failed\n");
exit(1);
}
}
//返回共享内存区域的标识符
if((shmaddr=shmat(shmid_goods,(char*)0,0))==(char*)-1)
{
perror("attach shared memory error\n");
exit(1);
}
/*创建一个共享内存,用于存放生产者和消费者在buffer中的索引号。
该索引指向了生产/消费的buffer的索引值。
*/
if((shmid_index=createshm(".",'z',2))==-1)
{
if(errno==EEXIST)
{
if((shmid_index=openshm(".",'z'))==-1)
{
exit(1);
}
}
else
{
perror("create shared memory failed\n");
exit(1);
}
}
else
{
is_noexist=1;
}
//attach the shared memory to the current process
if((indexaddr=shmat(shmid_index,(int*)0,0))==(int*)-1)
{
perror("attach shared memory error\n");
exit(1);
}
/*
索引初始化为0
*/
if(is_noexist)
{
indexaddr[0]=0;
indexaddr[1]=0;
}
/*该函数用于生成信号量集,并通过信号量集标识符设置信号量的值
mutex:1
empty:10
full:0
前两个参数用于生成key。
*/
if((semid=createsem(".",'t',3,0))==-1)
{
if(errno==EEXIST)
{
if((semid=opensem(".",'t'))==-1)
{
exit(1);
}
}
else
{
perror("semget error:");
exit(1);
}
}
else
{
union semun arg;
//seting value for mutex semaphore
arg.val=1;
if(semctl(semid,0,SETVAL,arg)==-1)
{
perror("setting semaphore value failed\n");
return -1;
}
//set value for synchronous semaphore
arg.val=num;
//the num means that the producer can continue to produce num products
if(semctl(semid,1,SETVAL,arg)==-1)
{
perror("setting semaphore value failed\n");
return -1;
}
//the last semaphore's value is default
//the default value '0' means that the consumer is not use any product now
}
int goods=0;
while(1)
{
p(semid,1);
sleep(3);
p(semid,0);
//producer is producing a product
goods=rand()%10;
///将货物buffer中编号为indexaddr[0]的buffer中放入货物
shmaddr[indexaddr[0]]=goods;
printf("producer:%d produces a product[%d]:%d\n",getpid(),indexaddr[0],goods);
///同时索引值+1。
indexaddr[0]=(indexaddr[0]+1)%10;
v(semid,0);
sleep(3);
v(semid,2);
}
}
#include <shm.h>
int main()
{
int num;
int shmid_goods,shmid_index,semid;
char* shmaddr=NULL;
int *indexaddr=NULL;
int is_noexist=0;
num=10;
//创建货物的共享内存区域,并且链接到进程用户空间。大小为10字节。
if((shmid_goods=createshm(".",'s',num))==-1)
{
if(errno==EEXIST)
{
if((shmid_goods=openshm(".",'s'))==-1)
{
exit(1);
}
}
else
{
perror("create shared memory failed\n");
exit(1);
}
}
//返回共享内存区域的标识符
if((shmaddr=shmat(shmid_goods,(char*)0,0))==(char*)-1)
{
perror("attach shared memory error\n");
exit(1);
}
/*创建一个共享内存,用于存放生产者和消费者在buffer中的索引号。
该索引指向了生产/消费的buffer的索引值。
*/
if((shmid_index=createshm(".",'z',2))==-1)
{
if(errno==EEXIST)
{
if((shmid_index=openshm(".",'z'))==-1)
{
exit(1);
}
}
else
{
perror("create shared memory failed\n");
exit(1);
}
}
else
{
is_noexist=1;
}
//attach the shared memory to the current process
if((indexaddr=shmat(shmid_index,(int*)0,0))==(int*)-1)
{
perror("attach shared memory error\n");
exit(1);
}
/*
索引初始化为0
*/
if(is_noexist)
{
indexaddr[0]=0;
indexaddr[1]=0;
}
/*该函数用于生成信号量集,并通过信号量集标识符设置信号量的值
mutex:1
empty:10
full:0
前两个参数用于生成key。
*/
if((semid=createsem(".",'t',3,0))==-1)
{
if(errno==EEXIST)
{
if((semid=opensem(".",'t'))==-1)
{
exit(1);
}
}
else
{
perror("semget error:");
exit(1);
}
}
else
{
union semun arg;
//seting value for mutex semaphore
arg.val=1;
if(semctl(semid,0,SETVAL,arg)==-1)
{
perror("setting semaphore value failed\n");
return -1;
}
//set value for synchronous semaphore
arg.val=num;
//the num means that the producer can continue to produce num products
if(semctl(semid,1,SETVAL,arg)==-1)
{
perror("setting semaphore value failed\n");
return -1;
}
//the last semaphore's value is default
//the default value '0' means that the consumer is not use any product now
}
int goods=0;
while(1)
{
p(semid,1);
sleep(3);
p(semid,0);
//producer is producing a product
goods=rand()%10;
///将货物buffer中编号为indexaddr[0]的buffer中放入货物
shmaddr[indexaddr[0]]=goods;
printf("producer:%d produces a product[%d]:%d\n",getpid(),indexaddr[0],goods);
///同时索引值+1。
indexaddr[0]=(indexaddr[0]+1)%10;
v(semid,0);
sleep(3);
v(semid,2);
}
}
#include <shm.h>
int main(int argc,char **argv)
{
int num;
int shmid_goods,shmid_index,semid;
char* shmaddr=NULL;
int* indexaddr=NULL;
int is_noexist=0;
num=10;
//create a shared memory as goods buffer
//注意,生产消费者的相同的共享区域用了同样的参数,
//所以会禅城同样的key值。
if((shmid_goods=createshm(".",'s',num))==-1)
{
if(errno==EEXIST)
{
if((shmid_goods=openshm(".",'s'))==-1)
{
exit(1);
}
}
else
{
perror("create shared memory failed\n");
exit(1);
}
}
//attach the shared memory to the current process
if((shmaddr=shmat(shmid_goods,(char*)0,0))==(char*)-1)
{
perror("attach shared memory error\n");
exit(1);
}
//create a shared memory as index
if((shmid_index=createshm(".",'z',2))==-1)
{
if(errno==EEXIST)
{
if((shmid_index=openshm(".",'z'))==-1)
{
exit(1);
}
}
else
{
perror("create shared memory failed\n");
exit(1);
}
}
else
{
is_noexist=1;
}
//attach the shared memory to the current process
if((indexaddr=shmat(shmid_index,(int*)0,0))==(int*)-1)
{
perror("attach shared memory error\n");
exit(1);
}
if(is_noexist)
{
indexaddr[0]=0;
indexaddr[1]=0;
}
//create a semaphore set including 3 semaphores
if((semid=createsem(".",'t',3,0))==-1)
{
if(errno==EEXIST)
{
if((semid=opensem(".",'t'))==-1)
{
exit(1);
}
}
else
{
perror("semget error:");
exit(1);
}
}
else
{
union semun arg;
//seting value for mutex semaphore
arg.val=1;
if(semctl(semid,0,SETVAL,arg)==-1)
{
perror("setting semaphore value failed\n");
return -1;
}
//set value for synchronous semaphore
arg.val=num;
//the num means that the producer can continue to produce num products
if(semctl(semid,1,SETVAL,arg)==-1)
{
perror("setting semaphore value failed\n");
return -1;
}
//the last semaphore's value is default
//the default value '0' means that the consumer is not use any product now
}
int goods=0;
while(1)
{
p(semid,2);
sleep(1);
p(semid,0);
///取出一个货物。
goods=shmaddr[indexaddr[1]];
printf("consumer:%d consumes a product[%d]:%d\n",getpid(),indexaddr[1],goods);
//索引值加一
indexaddr[1]=(indexaddr[1]+1)%num;
v(semid,0);
sleep(1);
v(semid,1);
}
}