当我们需要控制对内存资源的存取的时候,可以用一种简单的加锁的方法来控制,即互斥锁。但互斥锁有一个明显的缺点,就是它只有两个状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补来互斥锁的不足。条件变量通常和互斥锁一起使用。
【使用过程】
1.调用pthread_mutex_init()函数来初始化一个pthread_t类型的互斥锁
调用pthread_cond_init()函数来初始化一个pthread_cond_t类型的条件变量
2.创建线程
3.一个线程先调用pthread_mutex_lock()函数给互斥锁上锁,再调用无条件等待函数pthread_cond_wait()或者计时等待函数pthread_cond_timedwait()等待条件变量为真。调用此函数后,会先解锁,阻塞等待到信号后,再上锁并继续执行。此时再调用pthread_mutex_unlock()函数给互斥锁解锁。
4.另一个线程调用pthread_cond_signal()函数唤醒对应条件变量的一个线程(多个线程则按入队顺序唤醒),或者调用pthread_cond_broadcast()函数唤醒对应条件变量的所以线程。
【应用举例】
描述:三个进程,一个加加,一个输出偶数,一个输出奇数
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_cond_t cond;
pthread_mutex_t mutex1;
pthread_mutex_t mutex2;
int flag = 0;
int n;
/***********
*全局变量n加1
***********/
void *number()
{
while (1)
{
if (flag == 0)
{
n++;
flag = 1;
}
pthread_cond_signal(&cond); //发送信号
}
}
/********
*输出偶数
********/
void *even()
{
while (1)
{
pthread_mutex_lock(&mutex1);
if (flag == 1)
{
//阻塞等待信号
pthread_cond_wait(&cond, &mutex1);
if (n%2 == 0)
{
printf("even n = %d\n", n);
sleep(1);
flag = 0;
}
}
pthread_mutex_unlock(&mutex1);
}
}
/********
*输出奇数
********/
void *odd()
{
while (1)
{
pthread_mutex_lock(&mutex2);
if (flag == 1)
{
//阻塞等待条件变量为真
pthread_cond_wait(&cond, &mutex2);
if (n%2 == 1)
{
printf("odd n = %d\n", n);
sleep(1);
flag = 0;
}
}
pthread_mutex_unlock(&mutex2);
}
}
int main()
{
pthread_t tid1, tid2, tid3;
int ret;
pthread_mutex_init(&mutex1, NULL);//锁1初始化
pthread_mutex_init(&mutex2, NULL);//锁2初始化
pthread_cond_init(&cond, NULL); //初始化条件变量cond,条件变量为假
ret = pthread_create(&tid1, NULL, number, NULL);//创建线程1:n++
if (ret < 0)
{
perror("pthread_create");
exit(1);
}
ret = pthread_create(&tid2, NULL, even, NULL);//创建线程2:输出偶数
if (ret < 0)
{
perror("pthread_create");
exit(1);
}
ret = pthread_create(&tid3, NULL, odd, NULL); //创建线程3:输出奇数
if (ret < 0)
{
perror("pthread_create");
exit(1);
}
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);
pthread_mutex_destroy(&mutex1);
pthread_mutex_destroy(&mutex2);
pthread_cond_destroy(&cond);
}