linux下用程序实现生产者消费者问题

额,生产者消费者这个问题应该不算少见,如果是用程序还是蛮简单的吧,但是如果是叫用进程间通信,分析进程争用资源的现象,解决进程互斥。。。dbq,我承认我划水了,用共享内存来实现的,曲解一下题意,为了更快地完成作业(上天保佑老师不懂程序,不懂任务。。。)
借鉴学习了https://blog.csdn.net/qq_27664167/article/details/81277096,也就是各个函数的用法。至于思想的话,dbq,偶是个傻子。。。

有小姐姐表示看不懂我的程序,自己瞎定义的变量、函数名什么的太多了。唔,这个是按自己的风格来的,自己能看懂,other可能看不太懂,但毕竟是小姐姐嘛,还是要稍微照顾一下的(???程序又不对,说什么的,不祸害人的嘛)

 

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#define MAX_LEN 5//生产者最多生产的数量
#define TIME 20  //alarm时钟的时间,主程序运行20s,退出
#define CONSUME_TIME_LIMIT 1000 //随机consume生产时间,用来对rand取模
#define CONSUME_SPEED 500       //时间底限,consume生产时间最少500ms 
#define PRODUCE_TIME_LIMIT 2    //produce消费时间,单位s
#define PRODUCE_SPEED 1



typedef struct shmInfo{//用两下标,模拟数组
	int head_index;//头,生产者产生的产品
	int tail_index;//尾,消费者消费的产品
}shmInfo;

int wait_flag = 0;//使produce、consume死循环,不断执行,直到父进程alarm时间到,跳出循环
int produce_time;//sleep函数的参数
int consume_time;

int sharememory(int ipc_size,int flag);
int create_ipc(int ipc_size);
int get_ipc(int ipc_size);
int destroy_sharememory(int id);
int shmInfo_init();
int shmInfo_push();
int shmInfo_get();
void open_waiting();
void produce();
void consume();

int main(){
	shmInfo_init();//初始化,并创建共享内存空间
	
	int p1;
	int id = get_ipc(sizeof(shmInfo));
	srand((int)time(NULL));//随机数种子,在这设有没有啊
	//destroy_sharememory(id);

	while((p1 = fork()) == -1);//创建子进程
	if(p1 > 0){
		alarm(TIME);//这个是设计一的内容,别说不会,不会自己看上一篇文章
		signal(SIGALRM, open_waiting); 
		produce(); 
		
		kill(p1, SIGUSR1); 
		wait(0);

		destroy_sharememory(id);//销毁共享内存空间
		return 0;
	}
	else{
		signal(SIGUSR1, open_waiting);
		consume();

		for(int i = 0; i < MAX_LEN; i++)//消费完所有产品
			shmInfo_get();
		return 0;
	}
}



// ①ftok函数生成键值
// ②shmget函数创建共享内存空间
// ③shmat函数获取第一个可用共享内存空间的地址
// ④shmdt函数进行分离(对共享存储段操作结束时的步骤,并不是从系统中删除共享内存和结构)
// ⑤shmctl函数进行删除共享存储空间


int sharememory(int ipc_size,int flag){//就是生成共享存储空间,主要用的是shmget函数
                                       //然后ftok生成要用的参数
	int id;
	key_t key=ftok("/tmp",66);
// ---------------------------
// 每一个共享存储段都有一个对应的键值(key)相关联(消息队列、信号量也同样需要)。
// key_t ftok(const char *path ,int id);
// path为一个已存在的路径名
// id为0~255之间的一个数值,代表项目ID,自己取
// 返回值:成功返回键值(相当于32位的int)。出错返回-1
// ---------------------------

	if(key < 0){
		printf("get key error\n");
		return -1;
	}
	id = shmget(key,ipc_size,flag);
// ---------------------------
// 创建共享存储空间并返回一个共享存储标识符
// int shmget(key_t key, size_t size,int flag);
// key为ftok生成的键值
// size为共享内存的长度,以字节为单位
// flag为所需要的操作和权限,可以用来创建一个共享存储空间并返回一个标识符或者获得一个共享标识符。
// flag的值为IPC_CREAT:如果不存在key值的共享存储空间,且权限不为0,则创建共享存储空间,并返回一个共享存储标识符。如果存在,则直接返回共享存储标识符。
// flag的值为 IPC_CREAT | IPC_EXCL:如果不存在key值的共享存储空间,且权限不为0,则创建共享存储空间,并返回一个共享存储标识符。如果存在,则产生错误。
// 返回值:成功返回共享存储ID;出错返回-1
// ---------------------------

	if(id < 0){
		printf("get id error\n");
		return -1;
	}
	return id;
}
 

//下面这两个函数,就是权限不同,可以简单理解为,一个是创建空间,一个是返回存储标识符
int create_ipc(int ipc_size){//创建共享存储空间,并返回一个共享存储标识符
	return sharememory(ipc_size,IPC_CREAT|IPC_EXCL|0666);
}

int get_ipc(int ipc_size){//返回共享存储标识符
	return sharememory(ipc_size,IPC_CREAT|0666);
}


int destroy_sharememory(int id){//销毁空间,也就是靠shmctl函数
	return shmctl(id,IPC_RMID,NULL);
// ---------------------------
// 删除共享存储空间,也可以获取和改变共享内存的状态
// int shmctl(int shmid, int cmd, struct shmid_ds *buf);
// shmid就是shmget函数返回的共享存储标识符
// cmd有三个
// 常用删除共享内存的为IPC_RMID;
// IPC_STAT:得到共享内存的状态,把共享内存的shmid_ds结构复制到buf中;
// IPC_SET:改变共享内存的状态,把buf所指的shmid_ds结构中的uid、gid、mode复制到共享内存的shmid_ds结构内。
// (内核为每个共享存储段维护着一个结构,结构名为shmid_ds,里面存放着共享内存的大小,pid,存放时间等一些参数)
// buf就是结构体shmid_ds
// ---------------------------
}

int shmInfo_init(){//创建共享存储空间,并对数值初始化
	int id = create_ipc(sizeof(shmInfo));
	if(id < 0){
		printf("create sharememory error\n");
		return -1;
	}

	shmInfo *p = (shmInfo *)shmat(id,NULL,0);
	if(p < 0){
		printf("get sharememory addr error\n");
		p = NULL;
		return -1;
	}
	p->head_index = 0;
	p->tail_index = 0;

	return 0;
}

int shmInfo_push(){//添加数据,也就是靠shmat将结构体shmInfo提取出来,对ta直接进行操作
	int id = get_ipc(sizeof(shmInfo));
	if(id < 0){
		printf("get sharememory error\n");
		return -1;
	}

	shmInfo *p = (shmInfo *)shmat(id,NULL,0);
// ---------------------------
// 获取第一个可用共享内存空间的地址
// void *shmat(int shmid, const void *addr, int flag);
// shmid为shmget生成的共享存储标识符
// addr指定共享内存出现在进程内存地址的什么位置,直接指定为NULL让内核自己决定一个合适的地址位置
// flag为对数据的操作,如果指定为SHM_RDONLY则以只读方式连接此段,其他值为读写方式连接此段。
// ---------------------------

	if(p < 0){
		printf("get sharememory addr error\n");
		p = NULL;
		return -1;
	}

	if(p->head_index - p->tail_index < MAX_LEN){//可生产
		p->head_index ++;//生产就是下标+1
		printf("produce %d \n", p->head_index);
	}
	return 0;
}
int shmInfo_get(){
	int id = get_ipc(sizeof(shmInfo));
	if(id < 0){
		printf("get sharememory error\n");
		return -1;
	}
	shmInfo *p = (shmInfo *)shmat(id,NULL,0);
	if(p < 0){
		printf("get sharememory addr error\n");
		p = NULL;
		return -1;
	}
	if(p->head_index - p->tail_index > 0){//可消费
		p->tail_index ++;
		printf("consume %d\n",p->tail_index);
	}
	return 0;
}


void open_waiting(){
	wait_flag = 1;
}


void produce(){//生产
	while(!wait_flag){//等待alarm信号,调用open_waiting
		shmInfo_push();
		produce_time = rand() % PRODUCE_TIME_LIMIT + PRODUCE_SPEED; 
		// printf("produce_time:%d\n",produce_time);
		sleep(produce_time);
//把调用该函数的线程挂起一段时间,单位是微秒
	}
}
void consume(){//消费
	sleep(5);//事先挂起一会,生产
	while(!wait_flag){
		shmInfo_get(); 
		consume_time = rand() % CONSUME_TIME_LIMIT + CONSUME_SPEED;
		// printf("consume_time:%d\n",consume_time); 
		usleep(consume_time);//2个usleep会出问题???
	}
}

 

你可能感兴趣的:(操作系统课程设计,linux下的败犬系列)