42.1 线程状态转换

42.1.1 状态转换图

  

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

 #include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h> /** 两个线程定义的共享资源 */
typedef struct {
int res;
int counter; ///< 用于统计获取结果线程的数量
pthread_cond_t cond; ///< 条件变量
pthread_mutex_t mutex; ///< 互斥锁
}Result; /** 计算并将结果放置在 Result 中的线程运行函数 */
void *set_fn(void *arg)
{
Result *r = (Result *)arg;
int i = ;
int sum = ; for(; i <= ; i++){
sum += i;
} /** 将结果放置到 Result 中 */
r->res = sum; pthread_mutex_lock(&r->mutex);
/** 判断获取结果的线程是否达到指定的数量 */
while(r->counter < ){
pthread_mutex_unlock(&r->mutex);
usleep();
pthread_mutex_lock(&r->mutex);
}
pthread_mutex_unlock(&r->mutex); /** 通知唤醒等待的那个获取结果的线程 */
pthread_cond_broadcast(&r->cond); return (void *);
} /** 获得结果的线程运行函数 */
void *get_fn(void *arg)
{
Result *r = (Result *)arg; /** 对两个线程共享的判断条件进行保护(加锁) */
/** 两个线程对判断条件的操作是互斥的 */
pthread_mutex_lock(&r->mutex);
/** 有一个线程准备好了,则计数器 +1 */
r->counter++; /** 获取结果的线程等待 */
pthread_cond_wait(&r->cond, &r->mutex); /** 被唤醒后 */
pthread_mutex_unlock(&r->mutex); /** 去获取计算结果 */
int res = r->res;
printf("0x%lx get sum is %d\n", pthread_self(), res); return (void *);
} int main(void)
{
int err;
pthread_t cal, get1, get2; Result r;
r.counter = ;
pthread_cond_init(&r.cond, NULL);
pthread_mutex_init(&r.mutex, NULL); /** 启动获取结果的线程 */
if((err = pthread_create(&get1, NULL, get_fn, (void *)&r)) != ){
perror("pthread create error");
} if((err = pthread_create(&get2, NULL, get_fn, (void *)&r)) != ){
perror("pthread create error");
} /** 启动计算结果的线程 */
if((err = pthread_create(&cal, NULL, set_fn, (void *)&r)) != ){
perror("pthread create error");
} pthread_join(cal, NULL);
pthread_join(get1, NULL);
pthread_join(get2, NULL); pthread_cond_destroy(&r.cond);
pthread_mutex_destroy(&r.mutex); pthread_cond_destroy(&r.cond);
pthread_mutex_destroy(&r.mutex);
return ;
}

  编译运行结果如下:

  

42.2 读者-写者案例

  

  • 几种情况:

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

  完成第一种情况:

 #include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <unistd.h> typedef struct {
int value; /** 读者 */
pthread_cond_t rc;
pthread_mutex_t rm;
int r_wait; /** 写者 */
pthread_cond_t wc;
pthread_mutex_t wm;
int w_wait;
}Storage; /** 写入数据的函数 */
void set_data(Storage *s, int value)
{
s->value = value;
} /** 获取数据的函数 */
int get_data(Storage *s)
{
return s->value;
} /** 写者线程运行函数定义 */
void *set_th(void *arg)
{
Storage *s = (Storage *)arg;
int i = ;
for(; i <= ; i++){
/** 写入数据 */
set_data(s, i +);
printf("0x%lx(%-5d) write data : %d\n", pthread_self(), i, i + ); pthread_mutex_lock(&s->rm);
/** 判断读者线程是否准备好 */
while(!s->r_wait){
pthread_mutex_unlock(&s->rm);
sleep();
pthread_mutex_lock(&s->rm);
}
s->r_wait = ;
pthread_mutex_unlock(&s->rm); /** 通知读者线程读取数据 */
pthread_cond_broadcast(&s->rc); /** 写者线程自阻塞等待读者线程通知已经读取完毕,
* 然后唤醒写者线程继续写入数据 */
pthread_mutex_lock(&s->wm);
s->w_wait = ;
pthread_cond_wait(&s->wc, &s->wm);
pthread_mutex_unlock(&s->wm); }
return (void *);
} /** 读者线程运行函数定义 */
void *get_th(void *arg)
{
Storage *s = (Storage *)arg;
int i = ;
for(; i <= ; i++){
pthread_mutex_lock(&s->rm);
s->r_wait = ;
pthread_cond_wait(&s->rc, &s->rm);
pthread_mutex_unlock(&s->rm); /** 读者线程被唤醒后读取数据 */
int value = get_data(s);
printf("0x%lx(%-5d) read data: %d\n", pthread_self(), i, value); pthread_mutex_lock(&s->wm);
/** 判断写者线程是否准备好 */
while(!s->w_wait){
pthread_mutex_unlock(&s->wm);
sleep();
pthread_mutex_lock(&s->wm);
}
/** 唤醒写者线程 */
s->w_wait = ;
pthread_mutex_unlock(&s->wm);
pthread_cond_broadcast(&s->wc); }
return (void *);
} int main(void)
{
int err;
pthread_t rth, wth; Storage s;
s.r_wait = ;
s.w_wait = ;
pthread_mutex_init(&s.rm, NULL);
pthread_mutex_init(&s.wm, NULL);
pthread_cond_init(&s.rc, NULL);
pthread_cond_init(&s.wc, NULL); /** 创建一个读者线程和写者线程 */
if((err = pthread_create(&rth, NULL, get_th, (void *)&s)) != ){
perror("pthread create error");
} if((err = pthread_create(&wth, NULL, set_th, (void *)&s)) != ){
perror("pthread create error");
} pthread_join(rth, NULL);
pthread_join(wth, NULL); pthread_mutex_destroy(&s.rm);
pthread_mutex_destroy(&s.wm);
pthread_cond_destroy(&s.rc);
pthread_cond_destroy(&s.wc); return ;
}

四十二、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. SElinux解决web网站无法访问

    SElinux解决web网站无法访问工具/原料centos 6.5系统httpd web服务器 SELinux 设置为enforcing:强制模式,代表 SELinux 运作中 方法/步骤1. 1se ...

  2. bzoj3160(FFT+回文自动机)

    题目描述 https://www.lydsy.com/JudgeOnline/problem.php?id=3160 题解 先把问题转化一下,我们要求的是非连续对称回文子序列. ans=回文子序列数- ...

  3. [HNOI2007]梦幻岛宝珠(背包)

    给你N颗宝石,每颗宝石都有重量和价值.要你从这些宝石中选取一些宝石,保证总重量不超过W,且总价值最大为,并输出最大的总价值.数据范围:N<=100;W<=2^30,并且保证每颗宝石的重量符 ...

  4. Java面试题-基础知识

    参考文章:Java面试题-基础知识 基础能力 什么是值传递和引用传递 线程状态有哪些,它们之间是如何转换的 进程与线程的区别,进程间如何通讯,线程间如何通讯? HashMap的数据结构是什么?如何实现 ...

  5. 解题:NOI2018 你的名字(68pts暴力)

    题面 rt,如果省选没退役就补 SAM的优势:简单明了 先建S的SAM并标记所有节点,之后每次询问直接把T按广义SAM的方法插上去,统计新加的节点到根的状态代表的本质不同子串数,减掉被标记的部分就是T ...

  6. HEOI2013 Segment

    传说中的“李超树”. 大意:给你若干线段,试求横坐标x上的最上方一条线段的编号.无则输出零. 解:用线段树维护. 插入的时候保存自己这个区间上可能成为最大值的线段,被抛弃的则看情况下放. 查询时从最底 ...

  7. 【模板】2-SAT

    题目大意:给定 N 个点的 M 条约束,约束形式为:\(a_i \lor a_j = 1\). 题解:拆点什么的就不说了,在求出一组解的时候,考虑到 Tarjan 找环的过程中,scc 染色是按照拓扑 ...

  8. JMeter请求执行次数 你想执行几次就执行几次

    今天介绍下JMeter如何控制请求执行次数 主要有两种方式: 方式一:通过循环控制器控制每个请求的执行次数 例如:脚本执行规律是这样的,login-->customerPage-->sea ...

  9. [转]深入理解CSS中的层叠上下文和层叠顺序

    http://www.zhangxinxu.com/wordpress/2016/01/understand-css-stacking-context-order-z-index/ 零.世间的道理都是 ...

  10. bash 4

    1)获取字符串长度: str="jwwjww" #str=‘jwwjww’//单引号双引号都一样 echo ${#str} 结果:6 2)提取子字符串 echo ${#str:1: ...