linux下多线程生产者消费者实现的一个示例

linux下多线程生产者消费者实现的一个示例

生产者消费者问题是一个经典的进程或线程同步互斥问题,这里给出一个linux多线程实现的一个例子。linux将线程作为一个库,并不默认链接,所以在链接的时候需要加上-lpthread或-pthread参数。
这个例子使用信号量作为同步互斥机制,在一个共享的环形存储区中,创建多个生产者线程向缓冲区中写入数据,同事创建多个消费者线程从缓冲区中读出数据,缓冲区满时生产者线程等待,缓冲区空时,消费者线程等待,同时保证了只有一个线程在读或写。可以分别指定生产者和消费者线程的数量。
具体代码如下:
/*************************************************************************
	> File Name: pc.c
	> Author: gwq
	> Mail: 457781132@qq.com 
	> Created Time: 2014年11月03日 星期一 17时07分01秒
 ************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>

#define BUFFER_SIZE	10
#define SEM_KEY		1234		//信号量Key值

//定义循环缓冲队列及对其的一组操作
struct circle_buf {			//循环缓冲队列结构
	int r;				//读指针
	int w;				//写指针
	int buf[BUFFER_SIZE];		//缓冲区
};

int semid;				//信号量id
struct sembuf semaphore;		//定义一个信号量
struct circle_buf cbuf;

void writecbuf(struct circle_buf *cbuf, int val)	//向缓冲区写一个值
{
	cbuf->buf[cbuf->w] = val;
	cbuf->w = (cbuf->w + 1) % BUFFER_SIZE;		//写过后指针+1
}

int readcbuf(struct circle_buf *pcbuf)			//从当前指针读一个值,返回value
{
	int value = pcbuf->buf[pcbuf->r];
	pcbuf->buf[pcbuf->r] = -1;			//读过后置-1
	pcbuf->r = (pcbuf->r + 1) % BUFFER_SIZE;	//读过后read+1

	return value;
}

void outcbuf(struct circle_buf *pcbuf)
{
	int i = 0;
	printf("缓冲区各单元的值:");
	for (i = 0; i < BUFFER_SIZE; ++i) {
		printf("%d%c", pcbuf->buf[i],
				(i == BUFFER_SIZE - 1) ? '\n' : ' ');
	}
}

int initsembuf(void)			//创建信号量集,并初始化
{
	int sem = 0;
	//创建3个信号量
	if ((semid = semget(SEM_KEY, 3, IPC_CREAT | 0666)) >= 0) {
		sem = 1;
		//第0个信号量为mutex互斥信号量,初值为1,缓冲区互斥使用(mutex)
		semctl(semid, 0, SETVAL, sem);
		sem = BUFFER_SIZE;
		//第1个信号量为empty同步信号量,初值为10,当前空缓冲区数(empty)
		semctl(semid, 1, SETVAL, sem);
		sem = 0;
		//第2个信号量为full同步信号量,初值为0,当前慢缓冲区数(full)
		semctl(semid, 2, SETVAL, sem);
		return 1;
	} else {
		return 0;
	}
}

//对信号量的PV操作
void pmutex(void)
{
	semaphore.sem_num = 0;		//信号量索引为0,即第一个信号量
	semaphore.sem_op = -1;		//减1
	semaphore.sem_flg = SEM_UNDO;
	semop(semid, &semaphore, 1);
}

void vmutex(void)
{
	semaphore.sem_num = 0;		//信号量索引为0,即第一个信号量
	semaphore.sem_op = 1;		//加1
	semaphore.sem_flg = SEM_UNDO;
	semop(semid, &semaphore, 1);
}

void pempty(void)
{
	semaphore.sem_num = 1;		//信号量索引为1,即第二个信号量
	semaphore.sem_op = -1;		//减1
	semaphore.sem_flg = SEM_UNDO;
	semop(semid, &semaphore, 1);
}

void vempty(void)
{
	semaphore.sem_num = 1;		//信号量索引为1,即第二个信号量
	semaphore.sem_op = 1;		//加1
	semaphore.sem_flg = SEM_UNDO;
	semop(semid, &semaphore, 1);
}

void pfull(void)
{
	semaphore.sem_num = 2;		//信号量索引为2,即第三个信号量
	semaphore.sem_op = -1;		//减1
	semaphore.sem_flg = SEM_UNDO;
	semop(semid, &semaphore, 1);
}

void vfull(void)
{
	semaphore.sem_num = 2;		//信号量索引为2,即第三个信号量
	semaphore.sem_op = 1;		//加1
	semaphore.sem_flg = SEM_UNDO;
	semop(semid, &semaphore, 1);
}

void sigend(int sig)
{
	semctl(semid, 3, IPC_RMID);
	exit(0);
}

void *productthread(void *arg)
{
	int val = *(int *)arg;
	while (1) {
		pempty();
		pmutex();
		writecbuf(&cbuf, val);
		printf("生产者%d写入缓冲区的值=%d.\n", val, val);
		outcbuf(&cbuf);
		vmutex();
		vfull();
		//sleep(1);
	}
	return NULL;
}

void *consumerthread(void *arg)
{
	int cid = *(int *)arg;
	int val = 0;
	while (1) {
		pfull();
		pmutex();
		val = readcbuf(&cbuf);
		printf("消费者%d取走的产品的值=%d.\n", cid, val);
		outcbuf(&cbuf);
		vmutex();
		vempty();
		//sleep(1);
	}
	return NULL;
}

int main(int argc, char *argv[])
{
	//初始化信号量集
	while (!initsembuf()) {
		;
	}
	//收到信号结束程序
	signal(SIGINT, sigend);
	signal(SIGTERM, sigend);
	int i = 0;
	int ret = 0;
	//初始化生产者消费者数量
	int consnum = 0;
	int prodnum = 0;

	//初始化循环缓冲队列
	cbuf.r = 0;
	cbuf.w = 0;
	memset(cbuf.buf, 0, BUFFER_SIZE);

	printf("请输入生产者进程的数目:");
	scanf("%d", &prodnum);
	int *prosarg = (int *)malloc(prodnum * sizeof(int));
	pthread_t *prosid = (pthread_t *)malloc(prodnum * sizeof(pthread_t));
	printf("请输入消费者进程的数目:");
	scanf("%d", &consnum);
	int *consarg = (int *)malloc(consnum * sizeof(int));
	pthread_t *consid = (pthread_t *)malloc(consnum * sizeof(pthread_t));

	//启动生产者
	for (i = 0; i < prodnum; ++i) {
		prosarg[i] = i + 1;
		ret = pthread_create(&prosid[i], NULL, productthread,
				(void *)&prosarg[i]);
		printf("消费者prosid[%d] = %lu\n", i + 1, prosid[i]);
		if (ret != 0) {
			printf("创建生产者线程失败!");
			exit(EXIT_FAILURE);
		}
	}

	for (i = 0; i < consnum; ++i) {
		consarg[i] = i + 1;
		ret = pthread_create(&consid[i], NULL, consumerthread,
				(void *)&consarg[i]);
		printf("生产者consid[%d] = %lu\n", i + 1, consid[i]);
		if (ret != 0) {
			printf("创建消费者线程失败!");
			exit(EXIT_FAILURE);
		}
	}

	sleep(10);

	return 0;
}



  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值