浅谈生产者消费者模型(Linux系统下的两种实现方法)

2019-10-13 10:27:01丽君

注:如果把sem_wait()和sem_post()放到pthread_mutex_lock()与pthread_mutex_unlock()之间会如何呢?

答案是:死锁,因为我们不能预知线程进入共享区顺序,如果消费者线程先对mutex加锁,并进入,sem_wait()发现队列为空,阻塞,而生产者在对mutex加锁时,发现已上锁也阻塞,双方永远无法唤醒对方。

第二种是条件变量配合互斥锁实现

条件变量的常见用法是在不满足某些条件时,阻塞自己,直到有线程通知自己醒来。

而互斥量在这里的作用依然还是防止多线程对共享资源同时操作,造成未知结果。

生产者消费者的行为与之前相同,只不过原来只调用sem_wait()可以完成两步,1是检查条件,2是阻塞,现在条件变量需要我们自己来设定条件(所以说条件变量配合互斥锁比信号量的功能更强大,因为它可以自定义休眠条件,但是这对使用者的要求也提高了,必须理清逻辑关系避免死锁)

#include <stdio.h>
#include <pthread.h>

#define MAX 5

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t notfull = PTHREAD_COND_INITIALIZER; 	//是否队满
pthread_cond_t notempty = PTHREAD_COND_INITIALIZER; 	//是否队空

int top = 0;
int bottom = 0;

void* produce(void* arg)
{
	int i;
	for ( i = 0; i < MAX*2; i++)
	{
		pthread_mutex_lock(&mutex);
		while ((top+1)%MAX == bottom)
		{
			printf("full! producer is waitingn");
			pthread_cond_wait(¬full, &mutex);//等待队不满
		}

		top = (top+1) % MAX;
		printf("now top is %dn", top);
		pthread_cond_signal(¬empty);//发出队非空的消息

		pthread_mutex_unlock(&mutex);
	}
	return (void*)1;
}

void* consume(void* arg)
{
	int i;
	for ( i = 0; i < MAX*2; i++)
	{
		pthread_mutex_lock(&mutex);
		while ( top%MAX == bottom)
		{
			printf("empty! consumer is waitingn");
			pthread_cond_wait(¬empty, &mutex);//等待队不空
		}
		bottom = (bottom+1) % MAX;
		printf("now bottom is %dn", bottom);
		pthread_cond_signal(¬full);//发出队不满的消息

		pthread_mutex_unlock(&mutex);
	}

	return (void*)2;
}

int main(int argc, char *argv[])
{
	pthread_t thid1;
	pthread_t thid2;
	pthread_t thid3;
	pthread_t thid4;

	int ret1;
	int ret2;
	int ret3;
	int ret4;

	pthread_create(&thid1, NULL, produce, NULL);
	pthread_create(&thid2, NULL, consume, NULL);
	pthread_create(&thid3, NULL, produce, NULL);
	pthread_create(&thid4, NULL, consume, NULL);

	pthread_join(thid1, (void**)&ret1);
	pthread_join(thid2, (void**)&ret2);
	pthread_join(thid3, (void**)&ret3);
	pthread_join(thid4, (void**)&ret4);

	return 0;
}

注:

为什么信号量在互斥区外,而条件变量在互斥区内呢?

因为互斥锁本质上是二元信号量,和信号量互斥的原理相同,而且放在互斥区会死锁,而条件变量是和互斥锁协同配合的,

我们从pthread_cond_wait()和pthread_cond_signal()的内部实现就可以看出