线程同步-条件变量(cond)
生产者与消费者问题
再引入条件变量之前。我们先看下生产者和消费者问题:生产者不断地生产产品。同一时候消费者不断地在消费产品。
这个问题的同步在于两处:第一。消费者之间须要同步:同一件产品仅仅可由一人消费。
第二,当无产品可消费时,消费者需等待生产者生产后,才可继续消费,这又是一个同步问题。具体了解:生产者消费者问题。
条件变量
条件变量是利用线程间共享的全局变量进行同步的一种机制。而且条件变量总是和相互排斥锁结合在一起。
相关函数
pthread_cond_t //条件变量类型
pthread_cond_init
pthread_cond_destroy
pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *)
pthread_cond_timedwait
pthread_cond_signal
pthread_cond_broadcast
当中,须要着重理解的是pthread_cond_wait()方法。它有三个作用:
- 全部执行到此处的线程被堵塞。直到条件变量的唤醒。
- 在堵塞的同一时候释放锁。
- 当被唤醒后,又一次去获取锁。
唤醒线程的函数有两个:pthread_cond_signal和pthread_cond_broadcast。前者唤醒一个,后者唤醒全部的。
生产者与消费者演示样例代码
运用条件变量,我们来解决下生产者和消费者问题:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
struct goods
{
int id;
struct goods *next;
};
pthread_mutex_t m;
pthread_cond_t has_product;
struct goods *head;
void *producer(void *argv)
{
struct goods *p = NULL;
while (1)
{
pthread_mutex_lock(&m);
p = malloc(sizeof(struct goods));
p->id = rand() % 100;
p->next = head;
head = p;
printf("produce %d\n", p->id);
pthread_mutex_unlock(&m);
pthread_cond_signal(&has_product);
//printf("produce %d\n", p->id);
sleep(rand() % 2);
}
return (void *)0;
}
void *comsumer(void *argv)
{
struct goods *p = NULL;
while (1)
{
pthread_mutex_lock(&m);
//思考:pthread_cond_wait()的作用?
while (NULL == head)
pthread_cond_wait(&has_product, &m);
p = head;
head = head->next;
printf("comsume %d\n", p->id);
pthread_mutex_unlock(&m);
//printf("comsume %d\n", p->id);
free(p);
sleep(rand() % 2);
}
return (void *)0;
}
int main(void)
{
int i;
//初始化条件变量和相互排斥量
pthread_mutex_init(&m, NULL);
pthread_cond_init(&has_product, NULL);
head = NULL;
pthread_t pro[2], com[3];
for (i = 0; i < 2; i++)
pthread_create(&pro[i], NULL, producer, NULL);
for (i = 0; i < 3; i++)
pthread_create(&com[i], NULL, comsumer, NULL);
for (i = 0; i < 2; i++)
pthread_join(pro[i], NULL);
for (i = 0; i < 3; i++)
pthread_join(com[i], NULL);
//销毁条件变量和相互排斥量
pthread_mutex_destroy(&m);
pthread_cond_destroy(&has_product);
return 0;
}
在代码中。我们开启两个线程作为生产者,三个线程作为消费者。产品使用链表存储,而且每次生产和消费都在链表头部发生。