/*
* 生产者/消费者模型
* 给定仓库容积(N)
* 生成者生成的产品入库
* 消费者从仓库中取出产品消费
* 仓库满了时生产者不能继续生成
* 仓库为空时消费者不能继续消费
* 对仓库的访问是独占的
*
* semBin 控制独占访问
* semMax 控制仓库满
* semMin 控制仓库空
*
* 生产者 消费者
* P(semMax) P(semMin)
* P(semBin) P(semBin)
* (*product)++ (*product)--
* 输出产品信息
* V(semBin) V(semBin)
* V(semMin) V(semMax)
*
*/
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <sys/mman.h>
#include <semaphore.h>
#include <assert.h>
#include <signal.h>
#define PC_SHM_NAME "/pcshm"
#define PC_SEM_NAME_BIN "/pcsembin"
#define PC_SEM_NAME_MAX "/pcsemmax"
#define PC_SEM_NAME_MIN "/pcsemmin"
#define SHM_LENGTH 512 //共享内存长度
#define PRODUCT_MAX 30 //仓库容积
#ifndef FALSE
#define FALSE 0
#endif
#ifndef TRUE
#define TRUE 1
#endif
int exitFlag = 0; //退出标志
/*
* ctrl+c signal
*/
void ctrlcHandle(int signum)
{
exitFlag = 1;
}
int main(void)
{
int * product; //产品数,指向共享内存
int shmFd; //共享内存句柄
sem_t * semBin; //二进制旗语,控制仓库唯一性访问
sem_t * semMax; //计数旗语,控制产品上限
sem_t * semMin; //计数旗语,控制产品下限
_Bool isFirst = FALSE; //首次运行?
signal(SIGINT, ctrlcHandle);
//准备共享内存
shmFd = shm_open(PC_SHM_NAME,
O_RDWR | O_CREAT | O_EXCL,
0666);
if( shmFd >= 0 )
{//第一次创建
isFirst = TRUE;
ftruncate(shmFd, SHM_LENGTH);
}else
{//重新打开
shmFd = shm_open(PC_SHM_NAME, O_RDWR, 0666);
if(shmFd < 0)
{
perror("shm_open");
exit(EXIT_FAILURE);
}
}
//内存映射
product = (int *)mmap(NULL,
SHM_LENGTH,
PROT_READ|PROT_WRITE,
MAP_SHARED,
shmFd,
0);
if(product == MAP_FAILED)
{
perror("mmap");
shm_unlink(PC_SHM_NAME);
exit(EXIT_FAILURE);
}
if(isFirst)
{//首次创建共享内存,初始化
*product = 0;
}
//打开/创建旗语
if(isFirst)
{
semBin = sem_open(PC_SEM_NAME_BIN,
O_CREAT, 0666, 1);
semMax = sem_open(PC_SEM_NAME_MAX,
O_CREAT, 0666, PRODUCT_MAX);
semMin = sem_open(PC_SEM_NAME_MIN,
O_CREAT, 0666, 0);
}else
{
semBin = sem_open(PC_SEM_NAME_BIN, 0);
semMax = sem_open(PC_SEM_NAME_MAX, 0);
semMin = sem_open(PC_SEM_NAME_MIN, 0);
}
if( (semBin == SEM_FAILED) ||
(semMax == SEM_FAILED) ||
(semMin == SEM_FAILED) )
{
perror("sem_open");
munmap(product, SHM_LENGTH);
shm_unlink(PC_SHM_NAME);
exit(EXIT_FAILURE);
}
//主循环
while(!exitFlag)
{
#ifdef PRODUCE //生产者
//P(MAX)
if( sem_wait(semMax) != 0 )
continue;
//P(BIN)
if( sem_wait(semBin) != 0 )
{
sem_post(semMax);
continue;
}
//生产
(*product)++;
printf("produce:%d\n", *product);
//V(BIN)
assert( sem_post(semBin) == 0 );
//V(MIN)
assert( sem_post(semMin) == 0 );
#else //消费者
//P(MIN)
if( sem_wait(semMin) != 0 )
continue;
//P(BIN)
if( sem_wait(semBin) != 0 )
{
sem_post(semMin);
continue;
}
//消费
(*product)--;
printf("consume:%d\n", *product);
//V(BIN)
assert( sem_post(semBin) == 0 );
//V(MAX)
assert( sem_post(semMax) == 0 );
#endif
usleep(100000);
}
munmap(product, SHM_LENGTH);
shm_unlink(PC_SHM_NAME);
sem_close(semBin);
sem_close(semMin);
sem_close(semMax);
sem_unlink(PC_SEM_NAME_BIN);
sem_unlink(PC_SEM_NAME_MIN);
sem_unlink(PC_SEM_NAME_MAX);
return 0;
}