pthread_mutex_t 和 pthread_cond_t 配合使用的简要分析

2023-11-09

pthread_mutex_t 和 pthread_cond_t 配合使用的简要分析

 

1.原理

假设有两个线程同时访问一个全局变量 n,这个全局变量的初始值等于0。

Int  n = 0 ;

         消费者线程 A 进入临界区,访问 n,A 必须等到 n 大于 0 才能接着往下执行,如果 n== 0,那么 A 将一直等待。

         还有一个生产者线程 B,B 进入临界区,修改 n 的值,使得 n >0,当 n > 0 时,B 通知等待 n > 0 的消费者线程A。A 被 B 通知之后就可以接着往下执行了。

 

 

         以上情况造成死锁:

         当 A 进入临界区时,其他线程不能进入临界区,意味着 B 没有机会去修改 n, n 的值一直为 0,不满足A 继续执行的条件(n > 0),A 只能一直等待。

         消费者进程拿到互斥锁 --> 进入临界区 --> 发现共享资源 n 不满足继续执行的条件(n> 0) --> 等待 n > 0

         消费者进程占有互斥锁 --> 生产者进程无法进入临界区 --> 无法修改 n 的值 --> 生产者等待消费者释放互斥锁

         解决死锁的方案就是采用条件变量。

         通常情况下,对共享资源(比如 n)保护要用到锁操作,当一个进程进入临界区时会拿到互斥锁(lock 操作),然后其他进程拿不到互斥锁,也就无法进入临界区,因此当进程进入临界区,发现共享资源不满足继续向下执行的条件(n > 0)时,就应该释放锁,让其他进程修改共享资源,以满足自己所需的执行条件。

消费者进入临界区 --> 共享变量不满足继续向下执行的条件 --> 消费者等待在条件变量 --> 释放互斥锁 --> 生产者进入临界区 --> 修改条件变量 --> 生产者通知消费者:现在有多的资源了,快来使用 --> 消费者再次拿互斥锁 --> 消费资源 --> 释放互斥锁。如果有多个消费者进程等待在条件变量上,就可以形成等待队列。

生产者和消费者模型中互斥锁和条件变量的使用流程图如下,其中蓝色代表消费者的执行流,红色是生产者的执行流。

 

 

2.使用方法

         条件变量的使用主要有以下五个函数:

 

 
  1. /* 初始化一个条件变量 */

  2. int pthread_cond_init (pthread_cond_t* cond, pthread_condattr_t *cond_attr);

  3.  
  4. /* 销毁一个条件变量 */

  5. int pthread_cond_destroy(pthread_cond_t* cond);

  6.  
  7. /* 令一个消费者等待在条件变量上 */

  8. int pthread_cond_destroy(pthread_cond_t* cond);

  9.  
  10. /* 生产者通知等待在条件变量上的消费者 */

  11. int pthread_cond_signal(pthread_cond_t* cond);

  12.  
  13. /* 生产者向消费者广播消息 */

  14. int pthread_cond_broadcast(pthread_cond_t* cond);

 

 

        

 

消费者等待条件的伪代码:

 

 
  1. pthread_mutex_lock(&mutex); // 拿到互斥锁,进入临界区

  2. while( 条件为假)

  3. pthread_cond_wait(cond, mutex); // 令进程等待在条件变量上

  4. 修改条件

  5. pthread_mutex_unlock(&mutex); // 释放互斥锁

 

 

 

生产者通知消费者的伪代码:

 

 
  1. pthread_mutex_lock(&mutex); // 拿到互斥锁,进入临界区

  2. 设置条件为真

  3. pthread_cond_signal(cond); // 通知等待在条件变量上的消费者

  4. pthread_mutex_unlock(&mutex); // 释放互斥锁

 

 

 

以下是示例程序,演示了互斥锁和条件变量配合使用方法,由于是在Linux下写的程序,所以注释全是英文的。

condition_test.c:

 

 
  1. /***************************************************************

  2. * Copyright (C) 2016 chengonghao

  3. * All rights reserved.

  4. *

  5. * chengonghao@yeah.net

  6. ***************************************************************/

  7. #include <unistd.h>

  8. #include <pthread.h>

  9.  
  10. #define CONSUMERS_COUNT 2

  11. #define PRODUCERS_COUNT 1

  12.  
  13. pthread_mutex_t g_mutex ;

  14. pthread_cond_t g_cond ;

  15.  
  16. pthread_t g_thread[CONSUMERS_COUNT + PRODUCERS_COUNT] ;

  17. int share_variable = 0 ;// this is the share variable, shared by consumer and producer

  18.  
  19. void* consumer( void* arg )

  20. {

  21. int num = (int)arg ;

  22. while ( 1 )

  23. {

  24. /******* critical section begin *******/

  25. pthread_mutex_lock( &g_mutex ) ;

  26.  
  27. // if share_variable == 0, means consumer shell stop here

  28. while ( share_variable == 0 )

  29. {

  30. printf( "consumer %d begin wait a condition...\n", num ) ;

  31. // put a thread blocked ont a condition variable( here is g_cond),

  32. // and unlock the mutex( here is g_mutex )

  33. pthread_cond_wait( &g_cond, &g_mutex ) ;

  34. }

  35. // here means n != 0 and consumer can goes on

  36. // consumer consumed shared variable, so the number of shared variable shell minus

  37. printf( "consumer %d end wait a condition...\n", num ) ;

  38. printf( "consumer %d begin consume product\n", num ) ;

  39. -- share_variable ;

  40.  
  41. pthread_mutex_unlock( &g_mutex ) ;

  42. /******** critial section end *********/

  43. sleep( 1 ) ;

  44. }

  45.  
  46. return NULL ;

  47. }

  48.  
  49. void* producer( void* arg )

  50. {

  51. int num = (int)arg ;

  52. while ( 1 )

  53. {

  54. /******* critical section begin *******/

  55. pthread_mutex_lock( &g_mutex ) ;

  56.  
  57. // produce a shared variable

  58. printf( "producer %d begin produce product...\n", num ) ;

  59. ++ share_variable ;

  60. printf( "producer %d end produce product...\n", num ) ;

  61. // unblock threads blocked on a condition variable( here is g_cond )

  62. pthread_cond_signal( &g_cond ) ;

  63. printf( "producer %d notified consumer by condition variable...\n", num ) ;

  64. pthread_mutex_unlock( &g_mutex ) ;

  65.  
  66. /******** critial section end *********/

  67. sleep( 5 ) ;

  68. }

  69.  
  70. return 1 ;

  71. }

  72.  
  73.  
  74. int main( void )

  75. {

  76. // initiate mutex

  77. pthread_mutex_init( &g_mutex, NULL ) ;

  78. // initiate condition

  79. pthread_cond_init( &g_cond, NULL ) ;

  80.  
  81. // initiate consumer threads

  82. for ( int i = 0; i < CONSUMERS_COUNT; ++ i )

  83. {

  84. pthread_create( &g_thread[i], NULL, consumer, (void*)i ) ;

  85. }

  86. sleep( 1 ) ;

  87. // initiate producer threads

  88. for ( int i = 0; i < PRODUCERS_COUNT; ++ i )

  89. {

  90. pthread_create( &g_thread[i], NULL, producer, (void*)i ) ;

  91. }

  92. for ( int i = 0; i < CONSUMERS_COUNT + PRODUCERS_COUNT; ++ i )

  93. {

  94. pthread_join( g_thread[i], NULL ) ;

  95. }

  96.  
  97. pthread_mutex_destroy( &g_mutex ) ;

  98. pthread_cond_destroy( &g_cond ) ;

  99. }

 

 

 

编译程序:

 

cgh@ubuntu:~/condition_test$ gcc condition_test.c -o test –lpthread

 

 

运行程序:

 

1.      第一个框,消费者 1 和0 发现share_variable == 0,于是先后等待在条件变量上;

2.      第二个框,生产者 0 开始生产共享变量,即 ++ share_variable,然后通知等待在条件变量上的消费者;

3.      第三个框,消费者 1 被生产者唤醒,开始消费共享变量,即– share_variable;

4.      第四个框,生产者 0 继续生产共享变量,++ share_variable,然后通知等待在条件变量上的消费者;

5.      第五个框,消费者 0 被唤醒,开始消费共享变量,即– share_variable;

以此类推,以上描述简化了拿锁和释放锁的过程,可以结合上面的流程图来理解代码

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

pthread_mutex_t 和 pthread_cond_t 配合使用的简要分析 的相关文章

  • 使用 sed 将 old-link-url 替换为 new-link-url

    我正在 bash 中编写一个脚本 将 old link url 替换为 new link url 我的问题是 sed 由于斜杠而无法替换 url 如果我只输入一些文字就可以了 my code sed e s old link new lin
  • ARM 系统调用的接口是什么?它在 Linux 内核中的何处定义?

    我读过有关 Linux 中的系统调用的内容 并且到处都给出了有关 x86 架构的描述 0x80中断和SYSENTER 但我无法追踪 ARM 架构中系统调用的文件和进程 任何人都可以帮忙吗 我知道的几个相关文件是 arch arm kerne
  • /proc/PID 文件格式

    我想从中检索一些流程信息 proc目录 我的问题如下 中的文件是否有标准格式 proc PID 例如 有这个proc PID status文件与Name t ProcName在第一行 我可以在其他地方用空格代替这个文件吗 t或者类似的东西
  • 通过 SSH 将变量传递给远程脚本

    我正在通过 SSH 从本地服务器在远程服务器上运行脚本 首先使用 SCP 复制该脚本 然后在传递一些参数时调用该脚本 如下所示 scp path to script server example org another path ssh s
  • Xenomai 中的周期性线程实时失败

    我正在创建一个周期性线程 它在模拟输出上输出方波信号 我正在使用 Xenomai API 中的 Posix Skin 和 Analogy 我使用示波器测试了代码的实时性能 并查看了方波信号 频率为 1kHz 的延迟 我应该实现 250us
  • grails 上的同步块在 Windows 上有效,但在 Linux 上无效

    我有一个 grails 应用程序 它依赖于服务中的同步块 当我在 Windows 上运行它时 同步按预期工作 但当我在 ams linux 上运行时 会出现 StaleObjectStateException 该问题在以下示例中重现 cla
  • 使用脚本自动输入 SSH 密码

    我需要创建一个自动向 OpenSSH 输入密码的脚本ssh client 假设我需要通过 SSH 进入myname somehost用密码a1234b 我已经尝试过 bin myssh sh ssh myname somehost a123
  • Gradle 1.3:build.gradle 不构建类

    这里有一个新问题 我有一个 build gradle 文件apply plugin java在其中 并与 java 项目 包关联 当我跑步时gradle build从命令行我得到 compileJava UP TO DATE process
  • 我应该使用哪个 Linux 发行版作为 Xen 主机? [关闭]

    Closed 这个问题是基于意见的 help closed questions 目前不接受答案 我为家庭办公室订购了一台服务器 我想用 Xen 对其进行分区 我认为这将使事情保持干净并且更容易维护 我将运行 MySQL PostgreSQL
  • 如何从 Linux 的 shell 中删除所有以 ._ 开头的文件?

    确实如标题所示 我已将许多文件从 Mac 复制到 Raspberry Pi 这导致了许多以前缀开头的多余文件 我想删除以以下开头的文件夹中的每个文件 我该怎么做 尝试类似的方法 cd path to directory rm rf 或者 如
  • 无关的库链接

    我有一个可能有点愚蠢的问题 因为我很确定我可能已经知道答案了 假设你有静态库A 动态共享库B和你的linux下的程序C 假设库 A 调用库 B 中的函数 并且您的程序调用库 A 中的函数 现在假设 C 在 A 中调用的所有函数都不使用 B
  • 如何确保 numpy BLAS 库可用作动态加载库?

    The theano安装文档 http www deeplearning net software theano install html troubleshooting make sure you have a blas library指
  • 具有少量父设备属性的 udev 规则

    我需要复杂且通用的udev规则来确定插入任何 USB 集线器的特定端口的 USB 设备 所以 我必须结合设备树不同层的父属性 我有这个 udevadm info query all name dev ttyUSB0 attribute wa
  • 确保 config.h 包含一次

    我有一个库项目 正在使用 Linux 中的 autotools 套件移植到该项目 我对自动工具很陌生 本周 我已经了解了其操作的基础知识 我有一个关于如何保留内容的问题config h免遭重新定义 我惊讶地发现生成的config h文件也没
  • “grep -q”的意义是什么

    我正在阅读 grep 手册页 并遇到了 q 选项 它告诉 grep 不向标准输出写入任何内容 如果发现任何匹配 即使检测到错误 也立即以零状态退出 我不明白为什么这可能是理想或有用的行为 在一个程序中 其原因似乎是从标准输入读取 处理 写入
  • 如何获取 linux 实用程序 tail 的源代码?

    这个命令确实非常有用 但是我可以在哪里获取源代码以查看内部发生的情况 thanks tail 实用程序是 Linux 上 coreutils 的一部分 源压缩包 ftp ftp gnu org gnu coreutils coreutils
  • gentoo crontab:为什么这个简单的 crontab 不起作用?

    我使用 GENTOO 发行版 crontab e 35 12 root php5 home www cron php 当我手动运行时 php5 php5 home www cron php 这有效 它向我发送了一封电子邮件 然后我检查日期
  • 停止服务时单元陷入故障状态(状态=143)[关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 这是我的问题 我有 CentOS 和 java 进程在上面运行 Java进程是通过启动 停止脚本来操作的 它也创建了 java 实例的 p
  • 无法安装 WWW::Curl::Easy: SZBALINT/WWW-Curl-4.17.tar.gz : make NO

    我正在尝试在我的 Fedora 26 机器上安装 WWW Curl Easy gcc c I usr include D REENTRANT D GNU SOURCE O2 g pipe Wall Werror format securit
  • 为什么在 Linux 上字符串文字的内存地址与其他字符串文字的内存地址如此不同?

    我注意到字符串文字在内存中的地址与其他常量和变量 Linux 操作系统 非常不同 它们有许多前导零 未打印 Example const char h Hi int i 1 printf p n void h printf p n void

随机推荐

  • Python爬虫反反爬:CSS反爬加密彻底破解!

    刚开始搞爬虫的时候听到有人说爬虫是一场攻坚战 听的时候也没感觉到特别 但是经过了一段时间的练习之后 深以为然 每个网站不一样 每次爬取都是重新开始 所以 爬之前谁都不敢说会有什么结果 前两天 应几个小朋友的邀请 动心思玩了一下大众点评的数据
  • css动画效果之transition(动画过渡效果属性)

  • pandas dataframe 读取 xlsx 文件

    refer to https medium com kasiarachuta reading and writingexcel files in python pandas 8f0da449cc48 dframe pd read excel
  • github代码推送总是失败

    github代码推送问题 因为github仓库代码的推送总是失败 所以改了一个方案采用ssh的方式来进行代码的推送 并记录操作步骤 方案 https方式换成ssh方式 git ssh 生成 假如已经生成的话 可以略过此步骤 ssh keyg
  • Android启动service的方法

    在 Android 中启动 service 的方法如下 创建 service 的类 并在 AndroidManifest xml 文件中注册该 service 使用 Intent 类来启动 service 例如 Intent intent
  • [转]公司管理混乱,从哪里入手?

    案例分析 我们是一个40人左右的小公司 规模虽小 但管理起来感觉力不从心 经常碰到工人抵抗 情绪化 上班迟到 旷工 不服从管理 即使勉强接受 也不会用心去做 草草应付了事 每次都提议是否弄个规章制度 但也是白纸一张 到了月底 实施不了 因为
  • 使用OpenGL 立方体贴图

    openGL系列文章目录 文章目录 openGL系列文章目录 前言 一 OpenGL 立方体贴图 二 使用步骤 1 代码 2 着色器程序 运行结果 注意 源码下载 参考 前言 对于室外3D 场景 通常可以通过在地平线上创造一些逼真的效果 来
  • SpringBoot利用AOP写一个日志管理(Log)

    1 需求 目前有这么个问题 有两个系统CSP和OMS 这俩系统共用的是同一套日志操作 Log 目前想区分下这俩系统的日志操作 那没办法了 只能重写一份Log的日志操作 你也可以参照若依框架的日志系统实现 2 新建一张日志表 sys oper
  • libevent学习篇之一:libevent快速入门

    https www jianshu com p 8ea60a8d3abb LibEvent快速入门 简介 基本的socket变成是阻塞 同步的 每个操作除非已经完成 出错 或者超时才会返回 这样对于每一个请求 要使用一个线程或者单独的进程去
  • 岁月划过生命线(16.02 ~ 10 -提前转正)

    岁月划过生命线 16 02 10 提前转正 标签 coder 10月9号收到了提前转正通知后就想写些总结 总结在微店的一年里见过的人 读过的书 做过的事儿 不然怕很多有意思的细节以后都忘了 但一直找借口迟迟懒得动笔 这篇总结断断续续竟写了一
  • Linux驱动入门必须get的知识点-01.基本框架与操作

    0 编写编译驱动的Makefile 指定驱动的测试的路径 ROOM DIR nfs rootfs home 2 study 指定测试Demo的交叉编译工具链 DEMO DIR home linux 1 DataShare 0 交叉编译工具链
  • Mybatis-Plus代码生成器快速上手示例

    Mybatis Plus代码生成器 实验脚本 Table structure for parent list DROP TABLE IF EXISTS parent list CREATE TABLE parent list p id in
  • Audacity如何改变音频节奏?Audacity调整音频节奏方法

    很多人在录完音频后都会试听效果 经常会发现音频的节奏要么太快 要么太慢 可是自己又不愿意花时间 花人力 物力再去录制音频 为了解决这问题 我们可以用Audacity改变音频的节奏 加快或者减慢某个音频片段或者整个音频的节奏 只是很多人不懂怎
  • Windows 11 & Server 2022 HLK kit WHQL认证注意事项

    微软已经发布Windows 11 Server2022 HLK WHQL 测试套装 针对这一版HLK 有一个地方十分值得注意 在创建Porject的时候会出现 is windows driver Project 选择框 这一选项目前是用于工
  • (小米系统系列一)小米/红米BL解锁,解BL锁方法(亲测可用)

    文章参考自原作者 原作者链接 https www bilibili com read cv3305336 https www xiaomi cn post 17982230 http www miui com unlock download
  • Java Eclipse如何调试代码

    下面通过一个简单的例子来了解一下 Eclipse 调试程序的方法 public class Test1 public static void main String args for循环 如果for后面 内的条件一直成立 内的代码一直执行
  • Pandas基础操作

    Pandas基础 文章目录 Pandas基础 一 Series 二 DataFrame 三 索引值 四 索引和选取 loc和iloc函数讲解 五 行和列的操作 map apply applymap函数讲解 Pandas的函数应用 层级索引
  • 数据结构与算法之快速排序

    package com yg sort author GeQiLin date 2020 2 26 21 00 import java util Arrays public class QuickSort private static in
  • [SWPUCTF 2021 新生赛]easyupload2.0

    打开以后是一个文件上传的界面 然后用burp抓包看一下 传入一个php文件 发现php是不行滴 然后想到用phtml改一下后缀 看是否可以略过 然后发现掠过了 爆出来了路径 上传成功 直接用蚁建 lianjie 链接成功 然后目录寻找fla
  • pthread_mutex_t 和 pthread_cond_t 配合使用的简要分析

    pthread mutex t 和 pthread cond t 配合使用的简要分析 1 原理 假设有两个线程同时访问一个全局变量 n 这个全局变量的初始值等于0 Int n 0 消费者线程 A 进入临界区 访问 n A 必须等到 n 大于