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

《UNIX网络编程:卷2》P188-189:图10-17、10-18

把共享缓冲区用作一个环绕缓冲区:生产者填写最后一项后,回过头来填写第一项,消费者也这么做。

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

/*
 * prodcons1.c
 * P188 图10-17 生产者-消费者问题信号量解决方案的main函数
 */
#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <semaphore.h>
#include <pthread.h>

#define FILE_MODE   (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
#define NBUFF		10
#define SEM_MUTEX	"/mutex"
#define SEM_NEMPTY	"/nempty"
#define SEM_NSTORED	"/nstored"

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

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

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

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

	nitems = atoi(argv[1]);

	/*
	 * 创建三个信号量。指定O_EXCL标志,因为每个信号量都需要初始化为正确的值
	 */
	if ((shared.mutex = sem_open(SEM_MUTEX, O_CREAT | O_EXCL, FILE_MODE, 1)) == SEM_FAILED) {
		fprintf(stderr, "sem_open error: %s\n", strerror(errno));
		exit(1);
	}
	if ((shared.nempty = sem_open(SEM_NEMPTY, O_CREAT | O_EXCL, FILE_MODE, NBUFF)) == SEM_FAILED) {
		fprintf(stderr, "sem_open error: %s\n", strerror(errno));
		exit(1);
	}
	if ((shared.nstored = sem_open(SEM_NSTORED, O_CREAT | O_EXCL, FILE_MODE, 0)) == SEM_FAILED) {
		fprintf(stderr, "sem_open error: %s\n", strerror(errno));
		exit(1);	
	}

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

	/*
	 * 创建两个线程,一个作为生产者,一个作为消费者。
	 */
	if (pthread_create(&tid_produce, NULL, produce, NULL) != 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);
	}

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

	/*
	 * 删除三个信号量
	 */
	sem_unlink(SEM_MUTEX);
	sem_unlink(SEM_NEMPTY);
	sem_unlink(SEM_NSTORED);

	exit(0);
}

/*
 * prodcons1.c
 * P189 图10-18 produce和consume函数
 */
void *produce(void *arg)
{
	int		i;

	for (i = 0; i < nitems; i++) {
		sem_wait(shared.nempty);			// 生产者等待到缓冲区中有一个条目的空间
		sem_wait(shared.mutex);				// 二值信号量保护临界区
		shared.buff[i%NBUFF] = i;			// 生产者在缓冲区中存放条目
		sem_post(shared.mutex);	
		sem_post(shared.nstored);			// 增加一个已填写槽位
	}
	return(NULL);
}

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);
}

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

如果错误地对换了消费者函数中的两个sem_wait调用的顺序,那么可能产生死锁。


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