深入理解pthread_cond_wait()
在多线程同步互斥的应用场景下,通常会用到pthread_cond_wait()和pthread_cond_signal()函数。那么这两个函数到底是如何保证互斥同步的呢?
为了对上面的问题有个直观的了解,可以从下面的问题着手。下面两段这些程序有什么bug么?
a. 等待条件的线程执行的代码:
Thread 1:
{
……………………..
pthread_cond_wait(cv, mutex);
do_worker_task();
……………………..
}
b.唤醒等待线程的代码:
Pthread2
{
pthread_mutex_lock(mutx);
pthread_cond_signal(cv)
pthread_mutex_unlock(mutex);
}
要知道上面代码问题在哪,关键是必须对pthread_cond_wait()有深入的了解。为了对这个函数又直观的了解,下面给出了pthread_cond_wait(cv, mutex)正常执行过程中的几个重要子步骤伪码:
pthread_cond_wait(cv, mutex) 实际做的事情:
a. pthread_mutex_unlock(mutex);
b. do_real_cond_wait(cv); // 可能在这阻塞直到其他线程调用pthread_cond_signal(cv)或者 pthread_cond_broadcast(cv),才会往下执行
c. pthread_mutex_lock(mutex);
结合在多处理器、多线程、高并发的环境下,上面三个步骤就显得缺一不可,才能保证尽可能地互斥:
步骤a:保证其他线程此后也有等待、申请条件变量的同等机会
步骤b:在条件变量还没就绪的情况下,执行真正的阻塞
步骤c:当前线程得到条件变量之后,阻止其他等待条件变量的线程继续往下执行,而自己可以往下执行。
pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t*mutex)函数传入的参数mutex用于保护条件,因为我们在调用pthread_cond_wait时,如果条件不成立我们就进入阻塞,但是进入阻塞这个期间,如果条件变量改变了的话,那我们就漏掉了这个条件。因为这个线程还没有放到等待队列上,所以调用pthread_cond_wait前要先锁互斥量,即调用pthread_mutex_lock(),pthread_cond_wait在把线程放进阻塞队列后,自动对mutex进行解锁,使得其它线程可以获得加锁的权利。这样其它线程才能对临界资源进行访问并在适当的时候唤醒这个阻塞的进程。当pthread_cond_wait返回的时候又自动给mutex加锁。
实际上边代码的加解锁过程如下:
/************pthread_cond_wait()的使用方法**********/
pthread_mutex_lock(&qlock); /*lock*/
pthread_cond_wait(&qready, &qlock); /*block-->unlock-->wait() return-->lock*/
pthread_mutex_unlock(&qlock); /*unlock*/
/*****************************************************/