四十二、Linux 线程——线程同步之条件变量之线程状态转换
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 线程——线程同步之条件变量之线程状态转换的更多相关文章
- 四十一、Linux 线程——线程同步之条件变量
41.1 概念 41.1.1 条件变量的介绍 互斥锁的缺点是它只有两种状态:锁定和非锁定 条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足 条件变量内部是一个等待队列,放置等待 ...
- linux线程同步(2)-条件变量
一.概述 上一篇,介绍了互斥量.条件变量与互斥量不同,互斥量是防止多线程同时访问共享的互斥变量来保 ...
- Linux线程同步:条件变量
条件变量通过允许线程阻塞和等待另一个线程发送信号的方法弥补了互斥锁的不足,它常和互斥锁一起使用.使用时,条件变量被用来阻塞一个线程,当条件不满足时,线程往往解开相应的互斥锁并等待条件发生变化.一旦其它 ...
- Gradle 1.12用户指南翻译——第四十二章. Announce插件
本文由CSDN博客万一博主翻译,其他章节的翻译请参见: http://blog.csdn.net/column/details/gradle-translation.html 翻译项目请关注Githu ...
- linux 条件变量与线程池
条件变量Condition Variables 概述 1. 条件变量提供了另外一种线程同步的方式.如果没有条件变量,程序需要使用线程连续轮询(可能在临界区critical section内)方式检查条 ...
- 线程同步,条件变量pthread_cond_wait
与互斥锁不同,条件变量是用来等待而不是用来上锁的.条件变量用来自动阻塞一个线程,直到某特殊情况发生为止.条件变量使我们可以睡眠等待某种条件出现.条件变量是利用线程间共享的全局变量进行同步的一种机制,主 ...
- “全栈2019”Java第四十二章:静态代码块与初始化顺序
难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...
- NeHe OpenGL教程 第四十二课:多重视口
转自[翻译]NeHe OpenGL 教程 前言 声明,此 NeHe OpenGL教程系列文章由51博客yarin翻译(2010-08-19),本博客为转载并稍加整理与修改.对NeHe的OpenGL管线 ...
- 网站开发进阶(四十二)巧用clear:both
网站开发进阶(四十二)巧用clear:both 前言 我们在制作网页中用div+css或者称xhtml+css都会遇到一些很诡异的情况,明明布局正确,但是整个画面却混乱起来了,有时候在IE6下看的很正 ...
随机推荐
- POJ - 3984迷宫问题(最短路径输出)
题目链接:http://poj.org/problem?id=3984 题目: 迷宫问题 Time Limit: 1000MS Memory Limit: 65536K Total Submiss ...
- vue2.0项目实战(3)使用axios发送请求
在Vue1.0的时候有一个官方推荐的 ajax 插件 vue-resource,但是自从 Vue 更新到 2.0 之后,官方就不再更新 vue-resource. 关于为什么放弃推荐? -> 尤 ...
- 高DPI下界面错乱的解决方法和原理
来源: http://bbs.csdn.net/topics/370177760 我在win32 + c写的界面中解决办法,就是把字体的字号给固定了,这样做的结果就是,不管dpi是否有改变,界面中控件 ...
- CF Educational Codeforces Round 57划水记
因为是unrated于是就叫划水记了,而且本场也就用了1h左右. A.B:划水去了,没做 C:大水题,根据初三课本中圆的知识,可以把角度化成弧长,而这是正多边形,所以又可以化成边数,于是假设读入为a, ...
- hdu 3530 "Subsequence" (单调队列)
传送门 题意: 给出一个序列,求最长的连续子序列,使得 m ≤ Max-Min ≤ k 我的理解: 定义数组 a[] 存储输入的 n 个数: 定义两个双端队列: deque<int >qM ...
- feign无法注入service
https://segmentfault.com/q/1010000008531927
- (数学 尾0的个数) 51nod1003 阶乘后面0的数量
n的阶乘后面有多少个0? 6的阶乘 = 1*2*3*4*5*6 = 720,720后面有1个0. 收起 输入 一个数N(1 <= N <= 10^9) 输出 输出0的数量 输入样例 5 ...
- tcping 与 telnet命令粗略使用
使用tcping命令,在网上下载tcping文件,放入c盘的system32目录下,即可使用 使用tcping命令用来ping某个端口,能通的话,说明从外部到端口是没有问题的 使用telnet ...
- CodeForces12D 树状数组降维
http://codeforces.com/problemset/problem/12/D 题意 给N (N<=500000)个点,每个点有x,y,z ( 0<= x,y,z <=1 ...
- Linux学习杂谈
Linux学习相关的... --------- 1.Linux是免费的2.Linux是安全稳定的3.linux是开源的,却世界的工程师都在维护系统--------------------熟悉脚本开发语 ...