看段代码:
#include <pthread.h>
#include <stdlib.h>
#include <unistd.h>
int g_val=0;
static pthread_mutex_t g_Mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t g_ConVar = PTHREAD_COND_INITIALIZER;
void *thread_function(void *arg)
{
while(1)
{
/* 休眠 */
pthread_mutex_lock(&g_Mutex);
pthread_cond_wait(&g_ConVar, &g_Mutex);
/* 被唤醒后,打印数据 */
printf("g_val = %d \n",g_val);
pthread_mutex_unlock(&g_Mutex);
}
return NULL;
}
int main(void)
{
int i=0;
pthread_t ptdThread;
if ( pthread_create( &ptdThread, NULL, thread_function, NULL) )
{
printf("error creating thread.");
exit(0);
}
while(1)
{
pthread_mutex_lock(&g_Mutex);
g_val++;
pthread_cond_signal(&g_ConVar);
pthread_mutex_unlock(&g_Mutex);
sleep(1);
}
}
看到这样的代码时,可能会有这样的疑问:
①. pthread_cond_wait 为什么需要传递 mutex 参数?
②. 为什么要结合mutex一起使用?
我们先来看pthread_cond_wait内部做了什么事:
pthread_cond_wait() 所做的第一件事就是同时对互斥对象解锁(于是其它线程可以修改已链接列表),并等待条件 g_ConVar发生(这样当 pthread_cond_wait() 接收到另一个线程的“信号”时,它将苏醒)。现在互斥对象已被解锁,其它线程可以访问和修改已链接列表,可能还会添加项。
此时,pthread_cond_wait() 调用还未返回。对互斥对象解锁会立即发生,但等待条件 g_ConVar通常是一个阻塞操作,这意味着线程将睡眠,在它苏醒之前不会消耗 CPU 周期。这正是我们期待发生的情况。线程将一直睡眠,直到特定条件发生,在这期间不会发生任何浪费 CPU 时间的繁忙查询。从线程的角度来看,它只是在等待 pthread_cond_wait() 调用返回。
现在再来解疑上诉的两个问题:
pthread_cond_wait()函数传入的参数mutex用于保护条件,因为我们在调用pthread_cond_wait时,如果条件不成立我们就进入阻塞,但是进入阻塞这个期间,如果条件变量改变了的话,那我们就漏掉了这个条件。因为这个线程还没有放到等待队列上,所以调用pthread_cond_wait前要先锁互斥量,即调用pthread_mutex_lock(),pthread_cond_wait再把线程放进阻塞队列后,自动对mutex进行解锁,使得其它线程可以获得加锁的权利。这样其它线程才能对临界资源进行访问并在适当的时候唤醒这个阻塞的进程。当pthread_cond_wait返回的时候又自动给mutex加锁。
网友评论