参考:https://www.2cto.com/kf/201708/665818.html
https://blog.csdn.net/kerwin_zxc/article/details/7877066
说明:
条件变量两个操作:首先一个等待使用资源的线程等待条件变量被设置为真,第二个操作就是另一个线程使用完那块公共资源后,把条件设置为真。
条件变量与互斥锁的关系
要保证变量正确被修改,条件变量也需要受到保护,此时用了互斥锁来保护。如果不使用两者搭配的话,当一个线程只使用互斥锁的话,当其他线程到这个程序的时候就会来判断是否上锁,若上锁了就等待解锁,这个时间里可能会有很多线程来判断,然后阻塞在这里,当调用锁的线程释放锁后,那么被阻塞的线程又会来抢夺这个资源,从而造成了资源时间空间的浪费。而当加上了条件变量的时候,被阻塞的线程就会变得有序,在一个队列里排队,当接受到激活信号之前不会反复检查是否该锁已经释放,只需要一个通知(激活信号)来告诉这个线程,你所需要的那个锁已经释放了,现在你可以用了,此时整个过程就变的有序,而不是因为抢夺来消耗资源了。二者的关系操作可以形象看作从一个无序的占用资源变成一个有序的节约资源的一个改变,所以条件变量和互斥锁二者使用能够保证条件变量的正确修改。
pthread_cond_wait理解
在条件变量里面,锁的函数很重要,其中起到关键作用之一的函数便是这个等待函数吧。
条件变量是利用线程间共享的全局变量进行同步的一种机制,主要包括两个动作:一个线程等待”条件变量的条件成立”而挂起;另一个线程使”条件成立”(给出条件成立信号)。为了防止竞争,条件变量的使用总是和一个互斥锁结合在一起。
—pthread_cond_wait百度百科
函数原型:
int pthread_cond_wait(pthread_cond_t *cond,pthread_mutex_t *mutex)
该函数的两个动作:首先释放由第二个参数指向的锁,解锁后,把第一个参数cond的条件变量指向条件阻塞变量,直到条件信号被激活。
当一个线程在使用条件变量和互斥锁的时候,在条件不满足的时候(即条件信号为阻塞的时候),通过这个函数,该线程的锁会不断被解锁最后又被加锁,直到条件满足,被激活后此时会到重新上锁那一步,最后返回该函数,此时该函数执行语句结束,才会往下面的程序进行。
注意两点:
1) 在thread_cond_wait()之前,必须先lock相关联的mutex, 因为假如目标条件未满足,pthread_cond_wait()实际上会unlock该mutex, 然后block,在目标条件满足后再重新lock该mutex, 然后返回.–这点非常重要
2) 为什么是while(sum<100),而不是if(sum<100) ?这是因为在pthread_cond_signal()和pthread_cond_wait()返回之间,有时间差,假设在这个时间差内,还有另外一个线程t4又把sum减少到100以下了,那么t3在pthread_cond_wait()返回之后,显然应该再检查一遍sum的大小.这就是用while的用意
pthread_cond_wait() 用于阻塞当前线程,等待别的线程使用pthread_cond_signal()或pthread_cond_broadcast来唤醒它。
pthread_cond_wait() 必须与pthread_mutex_lock() 配套使用。pthread_cond_wait()函数一进入wait状态就会自动release mutex。当其他线程通过pthread_cond_signal()或pthread_cond_broadcast,把该线程唤醒,使pthread_cond_wait()通过(返回)时,该线程又自动获得该mutex。
pthread_cond_signal()必须和pthread_mutex_unlock(lock_s) 配套使用,在发送信号或者广播之前,一定要先unlock mutex,因为阻塞在条件变量上的线程被唤醒的时候,要对mutex加锁,如果该线程被唤醒,而此时通知线程仍然锁住互斥锁,泽被唤醒线程立刻阻塞在互斥锁上。
-
-
-
-
-
struct msg {
-
struct msg *next;
-
int num;
-
};
-
-
struct msg *head = NULL;
-
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
-
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
-
-
void *producer(void *p)
-
{
-
struct msg *mp;
-
for(;;)
-
{
-
mp = malloc( sizeof(struct msg));
-
mp->num = rand() % 2000 + 1;
-
printf( "Producer %d\n",mp->num);
-
pthread_mutex_lock(&lock);
-
mp->next = head;
-
head = mp;
-
pthread_mutex_unlock(&lock);
-
pthread_cond_signal(&has_product);
-
sleep(rand() % 5);
-
}
-
return NULL;
-
}
-
-
void *consumer(void *p)
-
{
-
struct msg *mp;
-
for(;;)
-
{
-
pthread_mutex_lock(&lock);
-
while(head == NULL)
-
pthread_cond_wait(&has_product,&lock);
-
mp = head;
-
head = mp->next;
-
pthread_mutex_unlock(&lock);
-
printf( "Consumer %d\n",mp->num);
-
free(mp);
-
sleep(rand() % 5);
-
-
}
-
return NULL;
-
}
-
-
-
int main()
-
{
-
pthread_t pid, cid;
-
srand(time( NULL));
-
-
pthread_create(&pid, NULL,producer, NULL);
-
pthread_create(&cid, NULL,consumer, NULL);
-
pthread_join(pid, NULL);
-
pthread_join(cid, NULL);
-
return 0;
-
}