注:如果把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()的内部实现就可以看出








