学习笔记:linux系统下通过PV操作来实现简单的生产者消费者模型

代码如下:

#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <stdio.h>
#include<string.h>
#include<sys/sem.h>
#include <sys/wait.h>
#define BUFFER_SIZE 1 /* 每次读写缓存大小,单位为字节,影响运行效率*/
#define STORE_FILE_NAME "./store" /* 源文件名*/
#define OFFSET 5 /* 复制的数据大小,单位为字节,即5个字节*/

/*
 判断信号集是否存在,存在返回1,不存在返回0 
*/
int sem_is_existing(int sem_id){
	struct semid_ds sem_info;
	if(semctl(sem_id,0,IPC_STAT,&sem_info)==-1){
		perror("this sem isnt existing!!!");
		return 0;
	}
	return 1;
}
/*
信号量初始化 
sem_id:sem_get返回的信号量集标识符 
n:信号量集中的编号,第一个编号为0 
init_value: 设置信号量的初始值 
*/

int init_sem(int sem_id, int n, int init_value) {
    union semun {
        int val;
        struct semid_ds *buf;
        unsigned short *array;
    };

    union semun sem_union;
    sem_union.val = init_value;

    if (semctl(sem_id, n, SETVAL, sem_union) == -1) {
        perror("Initialize semaphore");
        return -1;
    }

    return 0;
}
/*
获取该信号集束第n个信号量的可用资源数量 

*/
int getResourceNum(int sem_id,int n){
	return semctl(sem_id,n,GETVAL,NULL); 
} 
/* 从系统中删除信号量集的函数 */
int del_sem(int sem_id)
{
if (semctl(sem_id, 0, IPC_RMID,NULL) == -1)
{
perror("Delete semaphore");
return -1;
}
}

/*
 P 操作函数
 sem_id:信号量标识符IPC
 n:信号量集中第几个信号执行-1操作 
 
  */
int sem_p(int sem_id,int n)
{
struct sembuf sem_b;
sem_b.sem_num = n; /* 单个信号量的编号如果为0,即信号量集中的第一个信号量 */
sem_b.sem_op = -1; /* 表示P 操作 */
sem_b.sem_flg = SEM_UNDO; /* 系统自动释放将会在系统中残留的信号量*/
if (semop(sem_id, &sem_b, 1) == -1)
{
return -1;
}
return 0;
}

/* 
V 操作函数
 sem_id:信号量标识符IPC
 n:信号量集中第几个信号执行+1操作 
*/
int sem_v(int sem_id,int n)
{
struct sembuf sem_b;
sem_b.sem_num = n; /* 单个信号量的编号应该为0 */
sem_b.sem_op = 1; /* 表示V 操作 */
sem_b.sem_flg = SEM_UNDO; /* 系统自动释放将会在系统中残留的信号量*/
if (semop(sem_id, &sem_b, 1) == -1)
{
return -1;
}
return 0;
}

int main(){

pid_t pc;
int sem_mutex,sem_full,sem_empty;//定义信号量:互斥信号mutex 资源信号量empty, 可用资源信号量full 
if(sem_is_existing(sem_full)==1){//该信号集已存在 
	del_sem(sem_full);
	sem_full=semget(ftok("/",1),1,0666|IPC_CREAT);
}
else{
	sem_full=semget(ftok("/",1),1,0666|IPC_CREAT);
	printf("sem_full is %d\n",sem_full);
}
if(sem_is_existing(sem_empty)==1){//该信号集已存在 
	del_sem(sem_empty);
	sem_empty=semget(ftok("/",2),1,0666|IPC_CREAT);
}
else{
	sem_empty=semget(ftok("/",2),1,0666|IPC_CREAT);
	printf("sem_empty is %d\n",sem_empty);
}
if(sem_is_existing(sem_mutex)==1){//该信号集已存在 
	del_sem(sem_mutex);
	sem_mutex=semget(ftok("/",3),1,0666|IPC_CREAT);
}
else{
	
	sem_mutex=semget(ftok("/",3),1,0666|IPC_CREAT);
	printf("sem_mutex is %d\n",sem_mutex);
}
//设置互斥信号mutex的初值为1 sem_full的初值为0 sem_empty的初值为100 
init_sem(sem_mutex,0,1);
init_sem(sem_full,0,0);
init_sem(sem_empty,0,100);
pc=fork();
if(pc<0){
	printf("Error fork\n");
} 
else if(pc==0){//子进程,消费者进程
	char ch;
	char space=' ';	
	while(1){
		if(getResourceNum(sem_full,0)>0&&getResourceNum(sem_mutex,0)==1){
		printf("this is consumer process,before consuming,the empty resource is %d and the resource is %d....\n\n",semctl(sem_empty,0,GETVAL,NULL),semctl(sem_full,0,GETVAL,NULL));
		sem_p(sem_full,0);
		sem_p(sem_mutex,0); 
		int storeFile=open(STORE_FILE_NAME, O_RDWR);//打开提前准备好的仓库文件
		if(storeFile<0){
		printf("error open file!!!");
		exit(1);
		}
		lseek(storeFile,-2,SEEK_END);			
		read(storeFile,&ch,1);
		printf("the consumed resource is %c\n\n",ch);
		lseek(storeFile,-1,SEEK_CUR);
		write(storeFile,&space,1);
		close(storeFile);
		sem_v(sem_mutex,0);
		sem_v(sem_empty,0);
		
		printf("this is consumer process,after consuming,the empty resource is %d and the resource is %d....\n\n",semctl(sem_empty,0,GETVAL,NULL),semctl(sem_full,0,GETVAL,NULL));
		sleep(3);
			}
	}			
//		printf("consumer process end\n");
		
	} 
	
else{//父进程生产者
	printf("come to father \n");
	int i=0;
	char str[20];
	while(1){
		if(getResourceNum(sem_empty,0)>0&&getResourceNum(sem_mutex,0)==1){
		printf("this is producer process,before producing,the empty resource is %d and the resource is %d....\n\n",semctl(sem_empty,0,GETVAL,NULL),semctl(sem_full,0,GETVAL,NULL));
		sem_p(sem_empty,0);
		sem_p(sem_mutex,0);
		int storeFile=open(STORE_FILE_NAME, O_WRONLY | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);//打开提前准备好的仓库文件
		if(storeFile<0){
		printf("error open file!!!");
		exit(1);
		}
		i=i%9;
		sprintf(str,"%d\n",i);
		if(write(storeFile,str,strlen(str))<0){//将数字存入store文件 
		printf("error write to file!!!");
		close(storeFile);
		exit(1);
		}
		sem_v(sem_full,0);
		printf("the prodeced resource is %d\n\n",i);
		i++;
		close(storeFile);
		sem_v(sem_mutex,0);           
		printf("this is producer process,after producing,the empty resource is %d and the resource is %d....\n\n",semctl(sem_empty,0,GETVAL,NULL),semctl(sem_full,0,GETVAL,NULL)); 
		sleep(1);
			}
	}
	printf("producer process end\n");
	
} 

return 0;
}

注意事项:

1.要将整形数字转换成字符型再写入文件中,因为write直接写入整型数字是以二进制的形式写入,这样的文件是不可读的,即无法打开Store文件,报错:unknowType

2.在消费者读出字符后通过将文件指针前移(-1)然后再写入' '来实现删除字符的效果,注意因为生产者写入字符时是字符+'\n'(sprintf(str,"%d\n",i));所有当消费者打开文件时要将指针从SEEK_END前移两位(-2)否则无法读出有效字符,后续删除也会出错

如有错误欢迎指出

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值