关于linux条件变量的一点思考
Posted analogous_love
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于linux条件变量的一点思考相关的知识,希望对你有一定的参考价值。
设想有这样一种应用场景:
有A、B两个线程同时递增一个整型变量v,线程C在变量v是3的倍数时,输入v的值。因为涉及到多个线程同时读写同一个变量,所以肯定需要使用互斥体mutex对变量v进行保护,即同一时刻只能有且只有一个线程对v进行修改。假设A、B、C三个线程得到cpu时间片几率相等,如果不使用条件变量的话,在线程C中只能采取轮询的方式不断地去检测变量v的值是否是3的倍数。这样存在以下问题——碰巧的情况下,可能v的值的未发生改变时会被线程C检测多次。这样其实是在做无用功。
如果使用条件变量的话,当A或者B改变了v的值时,再去通知C去检测v的值是否是3的倍数,这样可以省去C的很多次的无用检测。在C不检测的情况下,C线程以休眠状态挂起。
代码如下:
#include <pthread.h>
#include <semaphore.h>
#include <unistd.h>
#include <stdio.h>
#include <fcntl.h>
#include <pthread.h>
#include <errno.h>
int index = 1;
pthread_mutex_t lock;
pthread_cond_t cond;
void* fun1(void* p)
while (index < 50)
pthread_mutex_lock(&lock);
index++;
printf("In fun1 : %d\\n",index);
pthread_cond_signal(&cond);//当有变化后,使用signal通知wait函数
pthread_mutex_unlock(&lock);
usleep(0.1);
void* fun2(void* p)
while (index < 50)
pthread_mutex_lock(&lock);
index++;
printf("In fun2 : %d\\n",index);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
usleep(0.1);
void* fun3(void*)
int i=0;
while (i < 70)
pthread_mutex_lock(&lock);
while ( index % 3 != 0)
pthread_cond_wait(&cond, &lock);//如果获得了互斥锁,但是条件不合适的话,wait会释放锁,不往下执行。当变化后,条件合适,将直接获得锁。
printf("%d\\n",index/3);
i++;
pthread_mutex_unlock(&lock);
usleep(0.1);
int main()
pthread_mutex_init(&lock, NULL);
pthread_cond_init(&cond, NULL);
pthread_t tid1,tid2,tid3;
pthread_create(&tid1, NULL, fun1, NULL);
pthread_create(&tid2, NULL, fun2, NULL);
pthread_create(&tid3, NULL, fun3, NULL);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
pthread_join(tid3, NULL);
return 0;
线程1或2改变了index值,去通知线程3去检测index值,这里只是通知线程3,不代表线程3一定会得到cpu时间片。所以可能会出现即使index是3的倍数时,由于线程3没有得到cpu时间片而不执行,也就是错过打印index值的机会(即使这个时候index是3的倍数)。如下图:
图中标红的地方,index的值都是3的倍数,由于线程3没有机会执行,所以并没有打印出来。
所以需要注意的地方是:使用条件变量时,虽然可以在条件满足时通知相关等待的线程,但等待的线程不一定会在条件满足时执行需要的动作,这是个几率问题。另外的,条件变量使用需要理解如下内容:
1.调用pthread_cond_wait或std::condition_variable.wait()(C11新增API)时会对相应的mutex进行解锁,然后线程睡眠等待条件触发。
2.当其他线程调用pthread_cond_signal/pthread_cond_broadcast 或 std::condition_variable.notify_one()/notify_all()(C11新增API)时,pthread_cond_wait或std::condition_variable.wait()所在的线程可能会苏醒过来,如果苏醒过来执行的话,pthread_cond_wait或std::condition_variable.wait()会对相应的mutex加锁。
产生条件变量的初衷是应对如下需求:
对某个共享变量进行检测看是否满足条件,避免了:
1.读取共享数据频繁的加锁解锁;
2.减少判断条件不满足的尝试的次数。
题外话
上述程序存在两个问题:
1. 线程3在线程1和2退出以后,挂起,导致整个进程无法正常退出。如何解决?
2. 如何让线程3打印出所有index是3的倍数的值?
参考:http://www.cnblogs.com/wzben/p/5431071.html
以上是关于关于linux条件变量的一点思考的主要内容,如果未能解决你的问题,请参考以下文章