42.1 线程状态转换

42.1.1 状态转换图

  

42.1.2 一个线程计算,多个线程获取的案例

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <pthread.h>
  4. #include <unistd.h>
  5.  
  6. /** 两个线程定义的共享资源 */
  7. typedef struct {
  8. int res;
  9. int counter; ///< 用于统计获取结果线程的数量
  10. pthread_cond_t cond; ///< 条件变量
  11. pthread_mutex_t mutex; ///< 互斥锁
  12. }Result;
  13.  
  14. /** 计算并将结果放置在 Result 中的线程运行函数 */
  15. void *set_fn(void *arg)
  16. {
  17. Result *r = (Result *)arg;
  18. int i = ;
  19. int sum = ;
  20.  
  21. for(; i <= ; i++){
  22. sum += i;
  23. }
  24.  
  25. /** 将结果放置到 Result 中 */
  26. r->res = sum;
  27.  
  28. pthread_mutex_lock(&r->mutex);
  29. /** 判断获取结果的线程是否达到指定的数量 */
  30. while(r->counter < ){
  31. pthread_mutex_unlock(&r->mutex);
  32. usleep();
  33. pthread_mutex_lock(&r->mutex);
  34. }
  35. pthread_mutex_unlock(&r->mutex);
  36.  
  37. /** 通知唤醒等待的那个获取结果的线程 */
  38. pthread_cond_broadcast(&r->cond);
  39.  
  40. return (void *);
  41. }
  42.  
  43. /** 获得结果的线程运行函数 */
  44. void *get_fn(void *arg)
  45. {
  46. Result *r = (Result *)arg;
  47.  
  48. /** 对两个线程共享的判断条件进行保护(加锁) */
  49. /** 两个线程对判断条件的操作是互斥的 */
  50. pthread_mutex_lock(&r->mutex);
  51. /** 有一个线程准备好了,则计数器 +1 */
  52. r->counter++;
  53.  
  54. /** 获取结果的线程等待 */
  55. pthread_cond_wait(&r->cond, &r->mutex);
  56.  
  57. /** 被唤醒后 */
  58. pthread_mutex_unlock(&r->mutex);
  59.  
  60. /** 去获取计算结果 */
  61. int res = r->res;
  62. printf("0x%lx get sum is %d\n", pthread_self(), res);
  63.  
  64. return (void *);
  65. }
  66.  
  67. int main(void)
  68. {
  69. int err;
  70. pthread_t cal, get1, get2;
  71.  
  72. Result r;
  73. r.counter = ;
  74. pthread_cond_init(&r.cond, NULL);
  75. pthread_mutex_init(&r.mutex, NULL);
  76.  
  77. /** 启动获取结果的线程 */
  78. if((err = pthread_create(&get1, NULL, get_fn, (void *)&r)) != ){
  79. perror("pthread create error");
  80. }
  81.  
  82. if((err = pthread_create(&get2, NULL, get_fn, (void *)&r)) != ){
  83. perror("pthread create error");
  84. }
  85.  
  86. /** 启动计算结果的线程 */
  87. if((err = pthread_create(&cal, NULL, set_fn, (void *)&r)) != ){
  88. perror("pthread create error");
  89. }
  90.  
  91. pthread_join(cal, NULL);
  92. pthread_join(get1, NULL);
  93. pthread_join(get2, NULL);
  94.  
  95. pthread_cond_destroy(&r.cond);
  96. pthread_mutex_destroy(&r.mutex);
  97.  
  98. pthread_cond_destroy(&r.cond);
  99. pthread_mutex_destroy(&r.mutex);
  100. return ;
  101. }

  编译运行结果如下:

  

42.2 读者-写者案例

  

  • 几种情况:

    • 1 个写者,1 个读者
    • 1 个写者,多个读者
    • 多个写者,多个读者

  完成第一种情况:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <pthread.h>
  4. #include <string.h>
  5. #include <unistd.h>
  6.  
  7. typedef struct {
  8. int value;
  9.  
  10. /** 读者 */
  11. pthread_cond_t rc;
  12. pthread_mutex_t rm;
  13. int r_wait;
  14.  
  15. /** 写者 */
  16. pthread_cond_t wc;
  17. pthread_mutex_t wm;
  18. int w_wait;
  19. }Storage;
  20.  
  21. /** 写入数据的函数 */
  22. void set_data(Storage *s, int value)
  23. {
  24. s->value = value;
  25. }
  26.  
  27. /** 获取数据的函数 */
  28. int get_data(Storage *s)
  29. {
  30. return s->value;
  31. }
  32.  
  33. /** 写者线程运行函数定义 */
  34. void *set_th(void *arg)
  35. {
  36. Storage *s = (Storage *)arg;
  37. int i = ;
  38. for(; i <= ; i++){
  39. /** 写入数据 */
  40. set_data(s, i +);
  41. printf("0x%lx(%-5d) write data : %d\n", pthread_self(), i, i + );
  42.  
  43. pthread_mutex_lock(&s->rm);
  44. /** 判断读者线程是否准备好 */
  45. while(!s->r_wait){
  46. pthread_mutex_unlock(&s->rm);
  47. sleep();
  48. pthread_mutex_lock(&s->rm);
  49. }
  50. s->r_wait = ;
  51. pthread_mutex_unlock(&s->rm);
  52.  
  53. /** 通知读者线程读取数据 */
  54. pthread_cond_broadcast(&s->rc);
  55.  
  56. /** 写者线程自阻塞等待读者线程通知已经读取完毕,
  57. * 然后唤醒写者线程继续写入数据 */
  58. pthread_mutex_lock(&s->wm);
  59. s->w_wait = ;
  60. pthread_cond_wait(&s->wc, &s->wm);
  61. pthread_mutex_unlock(&s->wm);
  62.  
  63. }
  64. return (void *);
  65. }
  66.  
  67. /** 读者线程运行函数定义 */
  68. void *get_th(void *arg)
  69. {
  70. Storage *s = (Storage *)arg;
  71. int i = ;
  72. for(; i <= ; i++){
  73. pthread_mutex_lock(&s->rm);
  74. s->r_wait = ;
  75. pthread_cond_wait(&s->rc, &s->rm);
  76. pthread_mutex_unlock(&s->rm);
  77.  
  78. /** 读者线程被唤醒后读取数据 */
  79. int value = get_data(s);
  80. printf("0x%lx(%-5d) read data: %d\n", pthread_self(), i, value);
  81.  
  82. pthread_mutex_lock(&s->wm);
  83. /** 判断写者线程是否准备好 */
  84. while(!s->w_wait){
  85. pthread_mutex_unlock(&s->wm);
  86. sleep();
  87. pthread_mutex_lock(&s->wm);
  88. }
  89. /** 唤醒写者线程 */
  90. s->w_wait = ;
  91. pthread_mutex_unlock(&s->wm);
  92. pthread_cond_broadcast(&s->wc);
  93.  
  94. }
  95. return (void *);
  96. }
  97.  
  98. int main(void)
  99. {
  100. int err;
  101. pthread_t rth, wth;
  102.  
  103. Storage s;
  104. s.r_wait = ;
  105. s.w_wait = ;
  106. pthread_mutex_init(&s.rm, NULL);
  107. pthread_mutex_init(&s.wm, NULL);
  108. pthread_cond_init(&s.rc, NULL);
  109. pthread_cond_init(&s.wc, NULL);
  110.  
  111. /** 创建一个读者线程和写者线程 */
  112. if((err = pthread_create(&rth, NULL, get_th, (void *)&s)) != ){
  113. perror("pthread create error");
  114. }
  115.  
  116. if((err = pthread_create(&wth, NULL, set_th, (void *)&s)) != ){
  117. perror("pthread create error");
  118. }
  119.  
  120. pthread_join(rth, NULL);
  121. pthread_join(wth, NULL);
  122.  
  123. pthread_mutex_destroy(&s.rm);
  124. pthread_mutex_destroy(&s.wm);
  125. pthread_cond_destroy(&s.rc);
  126. pthread_cond_destroy(&s.wc);
  127.  
  128. return ;
  129. }

四十二、Linux 线程——线程同步之条件变量之线程状态转换的更多相关文章

  1. 四十一、Linux 线程——线程同步之条件变量

    41.1 概念 41.1.1 条件变量的介绍 互斥锁的缺点是它只有两种状态:锁定和非锁定 条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足 条件变量内部是一个等待队列,放置等待 ...

  2. linux线程同步(2)-条件变量

    一.概述                                                    上一篇,介绍了互斥量.条件变量与互斥量不同,互斥量是防止多线程同时访问共享的互斥变量来保 ...

  3. Linux线程同步:条件变量

    条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用.使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化.一旦其它 ...

  4. Gradle 1.12用户指南翻译——第四十二章. Announce插件

    本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...

  5. linux 条件变量与线程池

    条件变量Condition Variables 概述 1. 条件变量提供了另外一种线程同步的方式.如果没有条件变量,程序需要使用线程连续轮询(可能在临界区critical section内)方式检查条 ...

  6. 线程同步,条件变量pthread_cond_wait

    与互斥锁不同,条件变量是用来等待而不是用来上锁的.条件变量用来自动阻塞一个线程,直到某特殊情况发生为止.条件变量使我们可以睡眠等待某种条件出现.条件变量是利用线程间共享的全局变量进行同步的一种机制,主 ...

  7. “全栈2019”Java第四十二章:静态代码块与初始化顺序

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

  8. NeHe OpenGL教程 第四十二课:多重视口

    转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...

  9. 网站开发进阶(四十二)巧用clear:both

    网站开发进阶(四十二)巧用clear:both 前言 我们在制作网页中用div+css或者称xhtml+css都会遇到一些很诡异的情况,明明布局正确,但是整个画面却混乱起来了,有时候在IE6下看的很正 ...

随机推荐

  1. LaTeX教程与下载

    LaTeX教程与下载如下: 其实,下载好CTEX 的步骤只有三步.第一步下载好CTEX ,第二步下载编辑器Texstudio ,第三步安装配置TexStudio 详细步骤: 第一步:下载CTEX La ...

  2. 单片机pwm控制基本原理详解

    前言 PWM是Pulse Width Modulation的缩写,它的中文名字是脉冲宽度调制,一种说法是它利用微处理器的数字输出来对模拟电路进行控制的一种有效的技术,其实就是使用数字信号达到一个模拟信 ...

  3. 工作笔记:/bin/bash^M: 坏的解释器: 没有那个文件或目录 问题解决

    问题原因: 由于windows上换行符为CR LF而在Linux下是 LF 导致出现上述问题 解决方案 1. 在windows下 可以使用nodepad打开该shell文件,然后将shell文件中的格 ...

  4. docker学习5--docker数据卷(volume)

    https://blog.csdn.net/dream_broken/article/details/52314993 1.什么是数据卷volume 为了了解什么是Docker Volume,首先我们 ...

  5. 【UR #3】链式反应

    http://uoj.ac/problem/50 %炮姐 好博客 树形结构 枚举根节点的儿子是哪两个 然后列出方程: 然后有EGF的影子! 倍增? 泰勒展开可以把未知数从函数里拿出来!并且变成1次项, ...

  6. 机器学习三剑客之matplotlib 数据绘图展示

    线型图: #导包 import matplotlib.pyplot as plt #导入字体库 from matplotlib.font_manager import FontProperties # ...

  7. TestNg1. 基本介绍注解介绍和如何让在maven中引用

    1.更适合测试人员,有很多的套件. maven中引用: <!-- https://mvnrepository.com/artifact/org.testng/testng --><d ...

  8. java8 List<对象> 转 Set、Map(高级)

    实体类 public class Student { private int id; private String name; private String score; private int cl ...

  9. Luogu P2852 [USACO06DEC]牛奶模式Milk Patterns

    题目链接 \(Click\) \(Here\) 水题.利用\(Height\)的性质维护一个单调栈即可. #include <bits/stdc++.h> using namespace ...

  10. iostat 磁盘io分析工具

    一:简介 iostat(I/O statistics)输入输出缩写,用来动态监视系统的磁盘操作活动.它能监视磁盘的活动统计情况,同时也能监视CPU的活动情况.缺点是,iostat不能对某一个具体的进程 ...