当前位置: 首页 > news >正文

【互斥锁和条件变量】何时互斥锁不够,还需要条件变量?

互斥锁的缺点是它只有两种状态:锁定和非锁定。而条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足。条件变量的内部实质上是一个等待队列,放置等待(阻塞)的线程,线程在条件变量上等待和通知,互斥锁用来保护等待队列(因为所有的线程都可以放入等待队列,所以等待队列成为了一个共享的资源,需要被上锁保护),因此条件变量通常和互斥锁一起使用。

条件变量允许线程等待特定条件(判断条件一般由用户自己给出)发生,当条件不满足时,线程通常先进入阻塞状态,等待条件发生变化。一旦其他的某个线程改变了条件,就可以唤醒等待队列中的一个或多个阻塞的线程。


原文和用法实例:https://blog.csdn.net/zjwson/article/details/65627638

http://www.blogjava.net/fhtdy2004/archive/2009/07/05/285519.html

线程同步:何时互斥锁不够,还需要条件变量?

很显然,pthread中的条件变量与Java中的wait,notify类似

假设有共享的资源sum,与之相关联的mutex 是lock_s.假设每个线程对sum的操作很简单的,与sum的状态无关,比如只是sum++.那么只用mutex足够了.程序员只要确保每个线程操作前,取得lock,然后sum++,再unlock即可.每个线程的代码将像这样add()
{
  pthread_mutex_lock(lock_s);
  sum++;
  pthread_mutex_unlock(lock_s);
}

  如果操作比较复杂,假设线程t0,t1,t2的操作是sum++,而线程t3则是在sum到达100的时候,打印出一条信息,并对sum清零.这种情况下,如果只用mutex, 则t3需要一个循环,每个循环里先取得lock_s,然后检查sum的状态,如果sum>=100,则打印并清零,然后unlock.如果sum<100,则unlock,并sleep()本线程合适的一段时间.

 这个时候,t0,t1,t2的代码不变,t3的代码如下
  print()
  {
    while (1)
    {
      pthread_mutex_lock(lock_s);
      if(sum<100)
      {
        printf(“sum reach 100!”);
        pthread_mutex_unlock(lock_s);
      }
      else
      {
        pthread_mutex_unlock(lock_s);
        my_thread_sleep(100);
        return OK;
      }
    }
  }

这种办法有两个问题
  1) sum在大多数情况下不会到达100,那么对t3的代码来说,大多数情况下,走的是else分支,只是lock和unlock,然后sleep().这浪费了CPU处理时间.
  2) 为了节省CPU处理时间,t3会在探测到sum没到达100的时候sleep()一段时间.这样却又带来另外一个问题,亦即t3响应速度下降.可能在sum到达200的时候,t3才会醒过来.
  3) 这样,程序员在设置sleep()时间的时候陷入两难境地,设置得太短了节省不了资源,太长了又降低响应速度.真是难办啊!

  这个时候,condition variable内裤外穿,从天而降,拯救了焦头烂额的你.

  你首先定义一个condition variable.
  pthread_cond_t cond_sum_ready=PTHREAD_COND_INITIALIZER;

  t0,t1,t2的代码只要后面加两行,像这样
  add()
  {
    pthread_mutex_lock(lock_s);
    sum++;
    pthread_mutex_unlock(lock_s);
    if(sum>=100)
    pthread_cond_signal(&cond_sum_ready);
  }
  而t3的代码则是
  print
  {
    pthread_mutex_lock(lock_s);
    while(sum<100)
    pthread_cond_wait(&cond_sum_ready, &lock_s);
    printf(“sum is over 100!”);
    sum=0;
    pthread_mutex_unlock(lock_s);
    return OK;
  }

注意两点:
  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加锁,如果该线程被唤醒,而此时通知线程仍然锁住互斥锁,泽被唤醒线程立刻阻塞在互斥锁上。

相关文章:

  • 【malloc和calloc】malloc和calloc函数区别
  • 【pthread_detach/pthread_join】pthread_detach()与pthread_join的区别?
  • 【时间复杂度】时间复杂度
  • 【Dll调试】DLL调试方法
  • 【机器学习】线性回归数学推导
  • 【VS消除警告】VS消除特定警告/安全函数警告C4996 strncpy unsafe……
  • CSDN 博客备份工具
  • 【FTP】linux FTP传文件到windows
  • 【VS】在VS中添加lib库的三种方法
  • 【合并lib】windows下多个lib合并的方法|查看lib是导入库还是静态库
  • 【python】anaconda 安装第三方包
  • 【IP/TCP】127.0.0.1和localhost和本机IP三者的区别
  • 【C/C++相互调用】C调用C++库和C++调用C库的方法
  • [STL]C++ STL中常见容器的时间复杂度
  • 【STL map】map用法、插入方法、pair和make_pair的区别
  • [Vue CLI 3] 配置解析之 css.extract
  • ES6系统学习----从Apollo Client看解构赋值
  • JavaScript 基础知识 - 入门篇(一)
  • Spring-boot 启动时碰到的错误
  • 搞机器学习要哪些技能
  • 关于extract.autodesk.io的一些说明
  • 互联网大裁员:Java程序员失工作,焉知不能进ali?
  • 一起来学SpringBoot | 第十篇:使用Spring Cache集成Redis
  • ​ ​Redis(五)主从复制:主从模式介绍、配置、拓扑(一主一从结构、一主多从结构、树形主从结构)、原理(复制过程、​​​​​​​数据同步psync)、总结
  • ​Kaggle X光肺炎检测比赛第二名方案解析 | CVPR 2020 Workshop
  • !!【OpenCV学习】计算两幅图像的重叠区域
  • # Swust 12th acm 邀请赛# [ E ] 01 String [题解]
  • #Java第九次作业--输入输出流和文件操作
  • #调用传感器数据_Flink使用函数之监控传感器温度上升提醒
  • (02)Hive SQL编译成MapReduce任务的过程
  • (Ruby)Ubuntu12.04安装Rails环境
  • (阿里云万网)-域名注册购买实名流程
  • (力扣记录)235. 二叉搜索树的最近公共祖先
  • (三)终结任务
  • (十一)手动添加用户和文件的特殊权限
  • (一)spring cloud微服务分布式云架构 - Spring Cloud简介
  • (已解决)报错:Could not load the Qt platform plugin “xcb“
  • (转)Linux NTP配置详解 (Network Time Protocol)
  • (转载)hibernate缓存
  • ... fatal error LINK1120:1个无法解析的外部命令 的解决办法
  • .NET CORE Aws S3 使用
  • .NET Core、DNX、DNU、DNVM、MVC6学习资料
  • /bin/rm: 参数列表过长"的解决办法
  • @AliasFor注解
  • []AT 指令 收发短信和GPRS上网 SIM508/548
  • [2669]2-2 Time类的定义
  • [Android]使用Git将项目提交到GitHub
  • [BUUCTF 2018]Online Tool
  • [c#基础]DataTable的Select方法
  • [cb]UIGrid+UIStretch的自适应
  • [CSAWQual 2019]Web_Unagi ---不会编程的崽
  • [Excel VBA]单元格区域引用方式的小结
  • [JavaWeb]—前端篇
  • [LeetCode]—Implement strStr() 寻找子串匹配第一个位置 (KMP)
  • [LeetCode]-Integer to Roman 阿拉伯数字转罗马数字