多线程编程之生产者消费者模型—C/C++语言实现

写该篇博客原因:生产者-消费者模型挺常用的,笔者记性又不好,人也比较笨,只好自己写着玩,以后自己用自己看自己写的博客就是。╮(๑•́ ₃•̀๑)╭ 

本博客为参照书《深入理解计算机系统》来通过信号量来实现生产者—消费者模型。

生产者—消费者模型:生产者和消费者线程共享一个有n个槽(slots)的有限缓冲区。生产者不停的生产新的项目(item),并把它们插入到缓冲区中。消费者线程不断地从缓冲区取出这些项目,然后消费他们。

 要解决的问题:因为插入和取出缓冲区的项目都需要更新共享变量,所以我们必须保证对缓冲区的访问是互斥的,并且需要保证缓冲区所有的数据都被消费者访问到。

在本例中,通过信号量来实现对缓冲区可写空槽位数量(生产者)和可读槽位数量(消费者)的计数(原子操作)。

在参照书后,写出一份C代码和一份C++代码,其中C++代码使用vector容器类存放数据,扩展性好。

代码如下(C):https://download.csdn.net/download/ty1121466568/10775953

C实现:

编译代码命令(懒得写makefile了):gcc -o test test.c producer_consumer_buf.c  -lpthread

头文件:producer_consumer_buf.h(定义对该模型的结构体,方便之后操作)

#ifndef _PRODUCER_CONSUMER_BUF_H_
#define _PRODUCER_CONSUMER_BUF_H_
#include 
#include 

#define P(sem)	sem_wait(sem)
#define V(sem)	sem_post(sem)
#define PV_INIT(sem,pshared,value)	sem_init(sem,pshared,value)	

typedef struct	producer_consumer_buf
{
	int *buf;	/*buffer array*/
	int slots_num;	/*max num slots*/
	int p_pos;	/*producer pos of buf*/
	int c_pos;	/*consumer pos of buf*/
	sem_t	mutex;	/*protects accesses to buf*/
	sem_t	slots;	/*producer can write num*/
	sem_t	items;	/*consumer can read num*/
}pcbuf_t;


int pcbuf_init(pcbuf_t *sp, int n);
int pcbuf_deinit(pcbuf_t *sp);
void pcbuf_insert(pcbuf_t *sp, int item);
void pcbuf_remove(pcbuf_t *sp, int *item);

#endif

c文件:producer_consumer_buf.c(对生产者消费者模型的代码实现)

#include 
#include 
#include "producer_consumer_buf.h"

/*
function:init the model struct 
params:model struct
*/
int pcbuf_init(pcbuf_t *sp, int n)
{
	sp->buf = (int *)malloc(sizeof(int)*n);
	
	if(sp->buf == NULL)
	{
		printf("can not malloc buf\n");	
		return -1;
	}

        memset(sp->buf,0x00,sizeof(int)*n);
	sp->slots_num = n;
	sp->slots_num = n;
	sp->p_pos = sp->c_pos = 0;
	PV_INIT(&sp->mutex,0,1);	/*pshared=0 only this process*/
	PV_INIT(&sp->slots,0,n);
	PV_INIT(&sp->items,0,0);
	
	return 0;
}

/*
function:destruct the model struct 
params:model struct
*/
int pcbuf_deinit(pcbuf_t *sp)
{
	free(sp->buf);
	return 0;
}

/*
function:producer
params:model struct,in num
*/
void pcbuf_insert(pcbuf_t *sp, int item)
{
	P(&sp->slots);	/*wait for available slot*/
	P(&sp->mutex);	/*lock the buffer*/
	sp->buf[(sp->p_pos++)%(sp->slots_num)] = item;	/*insert the item*/
	V(&sp->mutex);	/*unlock the buffer*/
	V(&sp->items);	/*update items available num*/
}

/*
function:consumer
params:model struct,out num
*/
void pcbuf_remove(pcbuf_t *sp, int *item)
{
	P(&sp->items);	/*wait for available items*/
	P(&sp->mutex);	/*lock the buffer*/
	*item = sp->buf[(sp->c_pos++)%(sp->slots_num)];	/*remove the item*/
	V(&sp->mutex);	/*unlock the buffer*/
	V(&sp->slots);	/*update slots available num*/
}

c文件:test.c(多线程编程实现测试)

#include 
#include 
#include 
#include 

#include "producer_consumer_buf.h"

void *producer(void *vargp);
void *consumer(void *vargp);



int main(int argc, char **argv)
{
	pthread_t tid1, tid2;
	pcbuf_t	sbuf;

	pcbuf_init(&sbuf, 100);

	pthread_create(&tid1, NULL, producer, (void *)&sbuf);
	pthread_create(&tid2, NULL, consumer, (void *)&sbuf);
	pthread_join(tid1, NULL);
	pthread_join(tid2, NULL);

	
	exit(0);
}


void *producer(void *vargp)
{
	int i = 1000;
	while(i--)
	{
		pcbuf_insert((pcbuf_t *)vargp, i);
		printf("insert pos=%d i=%d \n",(((pcbuf_t *)vargp)->p_pos)-1,i);
	}	
	return NULL;
}

void *consumer(void *vargp)
{
	int i = 0;
	while(1)
	{
		pcbuf_remove((pcbuf_t *)vargp, &i);
		printf("consume pos=%d i=%d\n",(((pcbuf_t *)vargp)->c_pos)-1,i);
	}	
	return NULL;
}

C++代码:由于打印存在延时之类,所以看到的打印信息并不严格,若要准确看到读写信息应该到临界段去打印。

编译选项:g++ -std=c++11  -pthread  -o test test.cpp

类定义:producer_consumer_buf.h

#ifndef _PRODUCER_CONSUMER_BUF_H_
#define _PRODUCER_CONSUMER_BUF_H_
#include 
#include 
#include 

using namespace std;
 
#define P_SEM(sem)	sem_wait(sem)
#define V_SEM(sem)	sem_post(sem)
#define PV_SEM_INIT(sem,pshared,value)	sem_init(sem,pshared,value)	


template 
class sem_solt
{
private:
	vector v_solts;
	int slots_num;	/*max num slots*/
	int p_pos;	/*producer pos of buf*/
	int c_pos;	/*consumer pos of buf*/
	sem_t	mutex;	/*protects accesses to buf*/
	sem_t	slots;	/*producer can write num*/
	sem_t	items;	/*consumer can read num*/

public:
	sem_solt(int snum = 1);
	void sem_insert(T item);
	void sem_remove(T &item);
};


template
sem_solt::sem_solt(int snum)
{
	
	if(snum>0)
	{
		v_solts.resize(snum);
	}

	slots_num = snum;	
	p_pos = c_pos = 0;
	PV_SEM_INIT(&mutex,0,1);	/*pshared=0 only this process*/
	PV_SEM_INIT(&slots,0,snum);
	PV_SEM_INIT(&items,0,0);
}

template
void sem_solt::sem_insert(T item)
{
	P_SEM(&slots);	/*wait for available slot*/
	P_SEM(&mutex);	/*lock the buffer*/
	v_solts[(p_pos++)%(slots_num)] = item;	/*insert the item*/
	V_SEM(&mutex);	/*unlock the buffer*/
	V_SEM(&items);	/*update items available num*/

}


template
void sem_solt::sem_remove(T &item)
{
	P_SEM(&items);	/*wait for available items*/
	P_SEM(&mutex);	/*lock the buffer*/
	item = v_solts[(c_pos++)%(slots_num)];	/*remove the item*/
	V_SEM(&mutex);	/*unlock the buffer*/
	V_SEM(&slots);	/*update slots available num*/
}

 
#endif
 

测试:test.c

#include 
#include 
#include 
#include 

#include "producer_consumer_buf.h"

using namespace std;

void *producer(void *vargp);
void *consumer(void *vargp);

typedef struct	str_test
{
	int *buf;	
	int slots_num;	
	int p_pos;	
	int c_pos;	
}st_t;

st_t	temp;
sem_solt newsolt(100);

int main(int argc, char **argv)
{

	thread tid1(producer,(void *)NULL);
	thread tid2(consumer,(void *)NULL);
	
	tid1.join();
	tid2.join();
	
	
	exit(0);
}

void *producer(void *vargp)
{
	int i = 1000;
	while(i--)
	{
		temp.slots_num=i;
		newsolt.sem_insert(temp);
		printf("producer:%d\n",i);
	}	
	return NULL;
}
void *consumer(void *vargp)
{
	int i = 1000;
	while(i--)
	{
		newsolt.sem_remove(temp);
		printf("consumer:%d\n",temp.slots_num);
	}	
	return NULL;
}

 

你可能感兴趣的:(学习过程)