条件变量:
条件变量本身不是锁!但它也可以造成线程阻塞。通常与互斥锁配合使用。给多线程提供一个会合的场所。
pthread_cond_init函数
初始化一个条件变量
int pthread_cond_init(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr);
参1:传出参数,调用前在外面先创建条件变量,pthread_cond_t cond;
参2:attr表条件变量属性,通常为默认值,传NULL即可
也可以使用静态初始化的方法,初始化条件变量:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_cond_destroy函数
销毁一个条件变量
int pthread_cond_destroy(pthread_cond_t *cond);
pthread_cond_wait函数
阻塞等待一个条件变量
int pthread_cond_wait(pthread_cond_t *restrict cond, pthread_mutex_t *restrict mutex);
函数作用:
1.阻塞等待条件变量cond(参1)满足
2.释放已掌握的互斥锁(解锁互斥量)相当于pthread_mutex_unlock(&mutex);
1.2.两步为一个原子操作。
3.当被唤醒,pthread_cond_wait函数返回时,解除阻塞并重新申请获取互斥锁pthread_mutex_lock(&mutex);(如果锁被其它线程抢走了,那么当前线程会继续阻塞,如果抢到锁了,那么就可以继续往下执行)
pthread_cond_signal函数
唤醒至少一个阻塞在条件变量上的线程
int pthread_cond_signal(pthread_cond_t *cond);
pthread_cond_broadcast函数
唤醒全部阻塞在条件变量上的线程
int pthread_cond_broadcast(pthread_cond_t *cond);
条件变量的优点:
相较于mutex而言,条件变量可以减少竞争。
如直接使用mutex,除了生产者、消费者之间要竞争互斥量以外,消费者之间也需要竞争互斥量,但如果链表中没有数据,消费者之间竞争互斥锁是无意义的。有了条件变量机制以后,只有生产者完成生产,才会引起消费者之间的竞争。提高了程序效率。
生产者消费者条件变量模型
我把理解全部写在代码注释里了。
/*借助条件变量模拟 生产者-消费者 问题*/
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <stdio.h>
/*链表作为共享数据,需被互斥量保护*/
struct msg {
struct msg *next;
int num;
};
struct msg *head;
/* 静态初始化 一个条件变量 和 一个互斥量*/
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void *consumer(void *p)
{
for (;;) {
pthread_mutex_lock(&lock);
while (head == NULL) //while是为了处理多个消费者的情况(很好想,比如一个消费者的pthread_cond_wait中先抢到了锁,并且消费完后又重新释放锁,那么此时另一个消费者的pthread_cond_wait中虽然拿到了锁,但是可能此时产品却没有了)
{
pthread_cond_wait(&has_product, &lock);//当它接收到signal/broadcast发来的信号后,就再次锁住mutex,一旦pthread_cond_wait锁定了互斥对象,那么它将返回并允许wait的线程继续执行。
}
//既要拿到锁,同时又要保证链表非空,都满足后才能执行接下来的代码(即开始消费)
struct msg * node = head;
head = node->next; //模拟消费掉一个产品
pthread_mutex_unlock(&lock);
printf("-Consume ---%d\n", node->num);
free(node);
node = NULL;
//sleep(rand() % 5);
}
}
void *producer(void *p)
{
for (;;) {
struct msg * node = malloc(sizeof(struct msg));
node->num = rand() % 1000 + 1; //模拟生产一个产品
printf("-Produce ---%d\n", node->num);
pthread_mutex_lock(&lock);
node->next = head;
head = node;
pthread_mutex_unlock(&lock);
pthread_cond_signal(&has_product); //将等待在该条件变量上的一个线程唤醒
//sleep(rand() % 5);
}
}
int main(int argc, char *argv[])
{
pthread_t pid, cid;
srand(time(NULL));
pthread_create(&pid, NULL, producer, NULL);
pthread_create(&cid, NULL, consumer, NULL);
pthread_join(pid, NULL);
pthread_join(cid, NULL);
return 0;
}