先来看看两者的概念:
互斥锁是一种用于多线程编程中,防止两条线程同时对同一公共资源(比如全局变量)进行读写的机制。
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待"条件变量的条件成立"而挂起;另一个线程使"条件成立"(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。
为什么要有条件变量呢?我们有互斥量不是就够了么? 条件变量为什么要和互斥锁一块儿使用呢?
下面我们来看一个例子:
假设有共享的资源sum,与之相关联的mutex 是lock_s.假设每个线程对sum的操作很简单的,与sum的状态无关,比如只是sum++.那么只用mutex足够了.程序员只要确保每个线程操作前,取得lock,然后sum++,再unlock即可.每个线程的代码将像这样
add()
{
pthread_mutex_lock(lock_s);
sum++;
pthread_mutex_unlock(lock_s);
}
从这个例子中可以看出好像我们使用互斥锁就完全可以完成我们的任务了,但是如果条件发生变化,我们要在sum的值大于100的时候将sum清零,此时该怎么做呢?例如下面的例子
假设线程t0,t1,t2的操作是sum++,而线程t3则是在sum大于100的时候,打印出一条信息,并对sum清零.
方案一:轮询,每次都lock->检查sum的值->unlock,当sum>100的时候,对sum进行清零
方案二:间歇性扫描,lock->检查sum的值->不大于100->sleep(某个值)->睡醒时候继续该过程,直到sum>100的时候,将sum清零.
方案一显然太low, 方案二的代码如下: 这个时候,t0,t1,t2的代码不变,t3的代码如下
print()
{
while (1)
{
pthread_mutex_lock(lock_s);
if(sum>100)
{
printf(“sum reach 100!”);
sum = 0;
pthread_mutex_unlock(lock_s);
}
else
{
pthread_mutex_unlock(lock_s);
my_thread_sleep(100);
return OK;
}
}
}
方案一的问题在于由于不断地轮询,lock/unlock会耗费大量的cpu时间,而且大多数情况下sum的值并不满足要求,做的都是无用功.
方案二的问题在于sleep()要睡眠多长时间呢,时间太短的话,会出现和方案一同样的问题,时间太长的话,sum到达100的时候又没有及时响应,可能等你响应的时候,sum已经远远大于100.
如何解决这个问题呢? 当你叫焦头烂额的时候,条件变量condition variable内裤外穿,从天而降!!!拯救了你.
你首先定义一个condition variable.
pthread_cond_t cond_sum_ready=PTHREAD_COND_INITIALIZER;
//t0,t1,t2的代码只要后面加两行,像这样
add()
{
pthread_mutex_lock(lock_s);
sum++;
pthread_mutex_unlock(lock_s);
if(sum>100)
{
pthread_cond_signal(&cond_sum_ready);
}
}
//而t3的代码则是
print()
{
pthread_mutex_lock(lock_s);
while(sum<100)
{
pthread_cond_wait(&cond_sum_ready, &lock_s);
printf(“sum is over 100!”);
sum=0;
pthread_mutex_unlock(lock_s);
break;
}
return OK;
}
注意:
在thread_cond_wait()之前,必须先lock相关联的mutex,因为假如目标条件未满足,pthread_cond_wait()实际上会unlock该mutex, 然后block,在目标条件满足后再重新lock该mutex, 然后返回.