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

《UNIX网络编程:卷2》P203-P204:图10-33、10-34

生产者和消费者之间使用多个缓冲区

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

/*
 * mycat2.c
 * P203 图10-33 全局变量和main函数
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <pthread.h>
#include <semaphore.h>

#define BUFFSIZE	2048
#define	NBUFF		8

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

struct {
	struct {
		char		data[BUFFSIZE];
		ssize_t		n;
	} buff[NBUFF];
	sem_t			mutex;
	sem_t			nempty;
	sem_t			nstored;
} shared;

int	fd;

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

	if (argc != 2) {
		fprintf(stderr, "usage: mycat2 <pathname>\n");
		exit(1);
	}

	if ((fd = open(argv[1], O_RDONLY)) < 0) {
		fprintf(stderr, "open error: %s\n", strerror(errno));
		exit(1);
	}

	/*
	 * 初始化三个信号量
	 */
	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, 1) == -1) {
		fprintf(stderr, "sem_init error: %s\n", strerror(errno));
		exit(1);
	}

	// set_concurrency(2);	// 该函数在Linux上无效
	
	/*
	 * 创建两个线程,一个作为生产者,一个作为消费者。
	 */
	if (pthread_create(&tid_produce, NULL, produce, NULL) == -1) {
		fprintf(stderr, "pthread_create error: %s\n", strerror(errno));
		exit(1);
	}
	if (pthread_create(&tid_consume, NULL, consume, NULL) == -1) {
		fprintf(stderr, "pthread_create error: %s\n", strerror(errno));
		exit(1);
	}

	/*
	 * 主线程等待这两个线程终止
	 */
	pthread_join(tid_produce, NULL);
	pthread_join(tid_consume, NULL);

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

	exit(0);
}

/*
 * mycat2.c
 * P204 图10-34 produce和consume函数
 */
void *produce(void *arg)
{
	int		i;

	for (i = 0; ; ) {
		sem_wait(&shared.nempty);		// 生产者等待到缓冲区中有一个条目的空间

		sem_wait(&shared.mutex);		// 二值信号量保护临界区
		/* 临界区 */
		sem_post(&shared.mutex);

		/* 
		 * 生产者每获得一个空闲缓冲区就调用read
		 * 如果read返回0(文件结束),生产者就在给nstored信号量加1后返回
		 */
		shared.buff[i].n = read(fd, shared.buff[i].data, BUFFSIZE);
		if (shared.buff[i].n == 0) {
			sem_post(&shared.nstored);
			return(NULL);
		}
		if (++i >= NBUFF)
			i = 0;

		sem_post(&shared.nstored);		// 缓冲区已填充 
	
	}
}

void *consume(void *arg)
{
	int		i;

	for (i = 0; ; ) {
		sem_wait(&shared.nstored);		// 消费者等待nstroed信号量

		sem_wait(&shared.mutex);		// 二值信号量保护临界区
		/* 临界区 */
		sem_post(&shared.mutex);

		/*
		 * 消费者线程取出缓冲区中的数据并把它们的内容写到标准输出
		 * 碰到长度为0的一个缓冲区表示已到达文件尾。
		 */
		if (shared.buff[i].n == 0)
			return(NULL);
		write(STDOUT_FILENO, shared.buff[i].data, shared.buff[i].n);

		if (++i >= NBUFF)
			i = 0;

		sem_post(&shared.nempty);		// 缓冲区已读取
	}
}

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