条件变量(Condtion Variable)是在多线程程序中用来实现“等待->唤醒”逻辑常用的方法。举个简单的例子,应用程序A中包含两个线程t1和t2。t1需要在bool变量test_cond为true时才能继续执行,而test_cond的值是由t2来改变的,这种情况下,如何来写程序呢?可供选择的方案有两种:

  • 第一种是t1定时的去轮询变量test_cond,如果test_cond为false,则继续休眠;如果test_cond为true,则开始执行。
  • 第二种就是上面提到的条件变量,t1在test_cond为false时调用cond_wait进行等待,t2在改变test_cond的值后,调用cond_signal,唤醒在等待中的t1,告诉t1 test_cond的值变了,这样t1便可继续往下执行。

    很明显,上面两种方案中,第二种方案是比较优的。在第一种方案中,在每次轮询时,如果t1休眠的时间比较短,会导致cpu浪费很厉害;如果t1休眠的时间比较长,又会导致应用逻辑处理不够及时,致使应用程序性能下降。第二种方案就是为了解决轮询的弊端而生的。然而条件变量在使用的过程中,比较容易出错,如何用得不正确的话,会适得其反的,接下来,我将详细分析如何来使用条件变量,希望能够给在使用条件变量过程中遇到问题的朋友有所帮助。
          在开始介绍之前,需要说明一下,在接下来的介绍中,需要用到互斥锁和条件变量相关的内容,在这里我以Linux下的pthread_mutex_t为互斥锁类型,pthread_cond_t为条件变量类型来进行介绍,对pthread不熟的朋友,可以参考一下linux下的manual。
          1. 下面是把刚开始举的例子翻译后的程序:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    pthread_mutex_t mutex;  ///< 互斥锁
    pthread_cond_t cond; ///< 条件变量
    bool test_cond = false;
    /// TODO 初始化mutex和cond
     
    /// thread 1:
    pthread_mutex_lock(&mutex); ///< 1
    while (!test_cond)
    {
    pthread_cond_wait(&cond, &mutex); ///< 2,3
    }
    pthread_mutex_unlock(&mutex); ///< 4
    RunThread1Func();
     
    /// thread 2:
    pthread_mutex_lock(&mutex); ///< 5
    test_cond = true;
    pthread_cond_signal(&cond);
    pthread_mutex_unlock(&mutex); ///< 6
     
    /// TODO 销毁mutex和cond

    通过上面的例子,下面我来介绍一下条件变量在使用过程中需要注意的几点(也是比较容易出错的):
          (1)条件变量的使用过程中,最为关键的一点是互斥锁的使用。细心的朋友应该发现了,我在上面的例子中标了1、2、3、4、5、6个标号。在这里1、4、5、6都是正常的lock/unlock,2、3是需要特别说明的。2是进入pthread_cond_wait后的,pthread_cond_wait调的pthread_mutex_unlock,这样做的目的是为了保证在thread1阻塞wait后,thread2获取同一把锁mutex的时候,能够正常获取(即5,6)。3是thread1被唤醒后,要退出pthead_cond_wait之前,pthread_cond_wait调的pthread_mutex_lock,这样做的目的是为了把mutex的控制权还给调用pthread_cond_wait的线程(即thread1)。整理一下基本的时序为:

    1
    2
    3
    thread 1 lock->thread 1 wait-> thread 1 unlock(in wait)
    ->thread 2 lock->thread 2 signal->thread 2 unlock
    ->thread 1 lock(in wait)->thread 1 unlock

    (2)条件变量使用的过程中,通常会加一个bool或者int的值test_cond来配合使用。这里需要注意的一点是一定要在signal之前来改变test_cond,这样才能保证wait的线程被唤醒后,能够取到正确的test_cond的值,否则后果是不可预测的。

条件变量(Condition Variable)详解的更多相关文章

  1. [转] 条件变量(Condition Variable)详解

    http://www.wuzesheng.com/?p=1668 条件变量(Condtion Variable)是在多线程程序中用来实现“等待->唤醒”逻辑常用的方法.举个简单的例子,应用程序A ...

  2. Python中的变量和作用域详解

    Python中的变量和作用域详解 python中的作用域分4种情况: L:local,局部作用域,即函数中定义的变量: E:enclosing,嵌套的父级函数的局部作用域,即包含此函数的上级函数的局部 ...

  3. Node.js中环境变量process.env详解

    Node.js中环境变量process.env详解process | Node.js API 文档http://nodejs.cn/api/process.html官方解释:process 对象是一个 ...

  4. 深入MySQL用户自定义变量:使用详解及其使用场景案例

    一.前言 在前段工作中,曾几次收到超级话题积分漏记的用户反馈.通过源码的阅读分析后,发现问题出在高并发分布式场景下的计数器上.计数器的值会影响用户当前行为所获得积分的大小.比如,当用户在某超级话题下连 ...

  5. python线程条件变量Condition(31)

    对于线程与线程之间的交互我们在前面的文章已经介绍了 python 互斥锁Lock / python事件Event , 今天继续介绍一种线程交互方式 – 线程条件变量Condition. 一.线程条件变 ...

  6. Python变量和字符串详解

    Python变量和字符串详解 几个月前,我开始学习个人形象管理,从发型.妆容.服饰到仪表仪态,都开始做全新改造,在塑造个人风格时,最基础的是先了解自己属于哪种风格,然后找到参考对象去模仿,可以是自己欣 ...

  7. JAVA JDK 环境变量配置 入门详解 - 精简归纳

    JAVA JDK 环境变量配置 入门详解 - 精简归纳 JERRY_Z. ~ 2020 / 9 / 13 转载请注明出处!️ 目录 JAVA JDK 环境变量配置 入门详解 - 精简归纳 一.为什么j ...

  8. Python安装与环境变量配置 入门详解 - 精简归纳

    Python安装与环境变量配置 入门详解 - 精简归纳 JERRY_Z. ~ 2020 / 9 / 24 转载请注明出处!️ 目录 Python安装与环境变量配置 入门详解 - 精简归纳 一.下载Py ...

  9. GoSDK的安装及环境变量配置 入门详解 - 精简归纳

    GoSDK的安装及环境变量配置 入门详解 - 精简归纳 JERRY_Z. ~ 2020 / 10 / 29 转载请注明出处!️ 目录 GoSDK的安装及环境变量配置 入门详解 - 精简归纳 一.进入G ...

随机推荐

  1. Flume是什么

    分布式流式实时收集日志文件系统,便于实时在线的流式计算,常配合 Storm 和 spark streming 使用. Flume is a distributed分布式的, reliable可靠的, ...

  2. P1498 南蛮图腾

    P1498 南蛮图腾 题目描述 自从到了南蛮之地,孔明不仅把孟获收拾的服服帖帖,而且还发现了不少少数民族的智慧,他发现少数民族的图腾往往有着一种分形的效果(看Hint),在得到了酋长的传授后,孔明掌握 ...

  3. Android 人脸识别

    Android人脸识别技术,可以参考下面的网站. http://www.faceplusplus.com.cn/ 本项目使用的就是该网站的api. 项目具体使用的技术代码 /** * 用来压缩图片的方 ...

  4. Hyper-V中的Linux无法配置网络地址的解决办法

    一周碰到2次在Hyper-V 2012中安装了Linux,也安装了IC 3.4.但是却无法配置IP地址的问题.因此造成很多不便,因此找机会把这个原因和解决办法进行了尝试. 这过程中感谢同事的提示,让我 ...

  5. 干货100+ 最超全的web开发工具和资源大集合

    干货100+ 最超全的web开发工具和资源大集合   作为Web开发者,这是好的时代,也是坏的时代.Web开发技术也在不断变化.虽然很令人兴奋,但是这也意味着Web开发人员需要要积极主动的学习新技术和 ...

  6. 一个初学者的辛酸路程-依旧Django

    回顾: 1.Django的请求声明周期?   请求过来,先到URL,URL这里写了一大堆路由关系映射,如果匹配成功,执行对应的函数,或者执行类里面对应的方法,FBV和CBV,本质上返回的内容都是字符串 ...

  7. 一个初学者的辛酸路程-前端cs

    一.主要内容 继续CSS 二.CSS 第一个: postion 网页有一类就是返回顶部,一直在右下角,还有打开一个网页顶部有个菜单,滚动滑轮,顶部永远在上面. position:  fiexd  == ...

  8. 设计模式之模板方法模式 templateMethod

    代码实现 public abstract class BankTemplateMethod { //具体方法 public void takeNumber(){ System.out.println( ...

  9. Java对字符串进行加密

    package anli1; import java.util.Scanner; public class example { public static void main(String[]args ...

  10. 个人支付宝监控并自动获取交易记录对接系统API

    我们都知道,支付宝支付API接口只有企业才能使用,但有一部分业务,可能我们不方便使用企业收款,但又想做到自动化,那怎么办呢 于是一个支付宝交易记录自动监控软件诞生了. 支付宝都有一个收款二维码,收款提 ...