读书笔记:第10章 Posix信号量 (4)

《UNIX网络编程:卷2》P194-P196:图10-21、10-22、10-23

多个生产者,单个消费者

------------------------------------------------------------------

/*
 * prodcons3.c
 * P194 图10-21 创建多个生产者线程的main函数
 */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <semaphore.h>
#include <pthread.h>

#define NBUFF		10
#define MAXNTHREADS	100
#define min(x,y)	((x) < (y) ? (x) : (y))

void *produce(void *arg);
void *consume(void *arg);

int		nitems;
int		nproducers;

struct {
	int		buff[NBUFF];		// 可以存放NBUFF个条目的缓冲区
	int		nput;				// 下一个待存入值的缓冲区项的下标
	int		nputval;			// 下一个待存入缓冲区的值
	sem_t	mutex;				// 二值信号量保护生产者和消费者的临界区
	sem_t	nempty;				// 统计共享缓冲区中的空槽位数	
	sem_t	nstored;			// 统计共享缓冲区中已填写的槽位数
} shared;

int main(int argc, char *argv[])
{
	int			i, count[MAXNTHREADS];
	pthread_t	tid_produce[MAXNTHREADS];
	pthread_t	tid_consume;

	if (argc != 3) {
		fprintf(stderr, "usage: prodcons3 <#items> <#producers>\n");
		exit(1);
	}
	nitems = atoi(argv[1]);							// 待存入缓冲区的总条目数
	nproducers = min(atoi(argv[2]), MAXNTHREADS);	// 待创建生产者线程的总数

	/*
	 * 初始化三个信号量
	 */
	if (sem_init(&shared.mutex, 0, 1) == -1) {
		fprintf(stderr, "sem_init error: %s\n", strerror(errno));
		exit(1);
	}
	if (sem_init(&shared.nempty, 0, NBUFF) == -1) {
		fprintf(stderr, "sem_init error: %s\n", strerror(errno));
		exit(1);
	}
	if (sem_init(&shared.nstored, 0, 0) == -1) {
		fprintf(stderr, "sem_init error: %s\n", strerror(errno));
		exit(1);
	}

	// set_concurrency(2);	// 该函数在Linux上无效

	/*
	 * 创建多个生产者线程,一个消费者线程
	 */
	for (i = 0; i < nproducers; i++) {
		count[i] = 0;
		if (pthread_create(&tid_produce[i], NULL, produce, &count[i]) != 0) {
			fprintf(stderr, "pthread_create error: %s\n", strerror(errno));
			exit(1);
		}
	}
	if (pthread_create(&tid_consume, NULL, consume, NULL) != 0) {
		fprintf(stderr, "pthread_create error: %s\n", strerror(errno));
		exit(1);
	}

	/*
	 * 主线程等待所有生产者和一个消费者终止
	 */
	for (i = 0; i < nproducers; i++) {
		pthread_join(tid_produce[i], NULL);
		printf("count[%d] = %d\n", i, count[i]);
	}
	pthread_join(tid_consume, NULL);

	/*
	 * 删除三个信号量
	 */
	sem_destroy(&shared.mutex);
	sem_destroy(&shared.nempty);
	sem_destroy(&shared.nstored);

	exit(0);
}

/*
 * prodcons3.c
 * P195 图10-22 所有生产者线程都执行的函数
 */
void *produce(void *arg)
{
	for ( ; ; ) {
		sem_wait(&shared.nempty);			// 生产者等待到缓冲区中有一个条目的空间
		sem_wait(&shared.mutex);			// 二值信号量保护临界区

		if (shared.nput >= nitems) {
			sem_post(&shared.nempty);		// 它们在最后一次走过循环时并没有往缓冲区存入条目
			sem_post(&shared.mutex);
			return(NULL);
		}
		shared.buff[shared.nput%NBUFF] = shared.nputval;	// 生产者在缓冲区中存放条目
		shared.nput++;
		shared.nputval++;

		sem_post(&shared.mutex);	
		sem_post(&shared.nstored);			// 增加一个已填写槽位
		*((int*)arg) += 1;
	}
}

/*
 * prodcons3.c
 * P196 图10-23 唯一的消费者线程执行的函数
 */
void *consume(void *arg)
{
	int		i;

	for (i = 0; i < nitems; i++) {
		sem_wait(&shared.nstored);			// 消费者等待nstroed信号量
		sem_wait(&shared.mutex);				// 二值信号量保护临界区

		if (shared.buff[i % NBUFF] != i)
			printf("buff[%d] = %d\n", i, shared.buff[i % NBUFF]);

		sem_post(&shared.mutex);
		sem_post(&shared.nempty);			// 增加一个空槽位
	}
	return(NULL);
}

你可能感兴趣的:(读书笔记,《UNIX网络编程》)