Linux进程间通讯—旗语

本文详细阐述了生产者消费者模型的实现原理及关键步骤,通过使用共享内存和信号量来解决仓库的唯一性访问、满载限制和空载状态问题。包括创建共享内存、初始化信号量、主循环中的生产者和消费者操作,以及如何处理信号中断以优雅地退出程序。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

/*
 *	生产者/消费者模型
 *	给定仓库容积(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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值