条件变量不是锁,但通常与互斥锁配合使用。互斥锁是用来访问共享资源加上的一把“锁”,实现共享资源某个时间只能有一个线程访问的互斥作用;而条件变量实现“等待----唤醒”的同步作用:当线程符合某个条件就会唤醒(signal/broadcast)正在等待(wait/timedwait)的其他线程继续执行。简而言之,互斥锁用于上锁,条件变量用于等待。
初始化
条件变量定义时静态初始化:
pthread_cond_t g_tConVar = PTHREAD_COND_INITIALIZER;
与互斥锁初始化一样,还可以调用pthread_cond_init函数动态初始化为默认属性NULL:
int pthread_cond_init(pthread_cond_t *restrict cond,
const pthread_condattr_t *restrict attr);
int pthread_cond_destroy(pthread_cond_t *cond);
等待/通知
//等待绝对时间abstime
int pthread_cond_timedwait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex,
const struct timespec *restrict abstime);
// 阻塞等待条件变量
// 函数内部其实执行了:解锁 -> 进入休眠 -> 唤醒之后上锁
int pthread_cond_wait(pthread_cond_t *restrict cond,
pthread_mutex_t *restrict mutex);
//唤醒所有阻塞cond的
int pthread_cond_broadcast(pthread_cond_t *cond);
//只唤醒一个线程
int pthread_cond_signal(pthread_cond_t *cond);
例子
结合互斥锁与条件变量编写测试例子:
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
int i = 0;
pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t g_condvar = PTHREAD_COND_INITIALIZER;
void *pthreadFunc(void *pvoid)
{
while(1)
{
pthread_mutex_lock(&g_mutex);
printf("pthreadFunc i: %d\n", ++i); // 改变变量的值
pthread_cond_signal(&g_condvar); // 唤醒其他在休眠的线程
pthread_mutex_unlock(&g_mutex);
sleep(1); // 延时一秒
}
}
int main()
{
pthread_t tid;
pthread_create(&tid, NULL, pthreadFunc, NULL);
while(1)
{
pthread_mutex_lock(&g_mutex);
pthread_cond_wait(&g_condvar, &g_mutex); // 阻塞等待唤醒
printf("main i: %d\n", i); // 读取变量的值
pthread_mutex_unlock(&g_mutex);
}
return 0;
}
程序说明:首先创建一个线程,这个线程负责改变变量i的值,main函数里面负责读取i的值。main函数上锁之后调用pthread_cond_wait进行解锁然后进入休眠等待唤醒,当pthreadFunc函数改变i之后唤醒main函数,此时再次上锁进行读取i的值。
输出结果:
pthreadFunc i: 1
main i: 1
pthreadFunc i: 2
main i: 2
pthreadFunc i: 3
main i: 3
^C