四十二、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下看的很正 ...
随机推荐
- portainer图形化监控
步骤1,在Swarm集群中创建一个新的覆盖网络:$ docker network create --driver overlay --attachable portainer_agent_networ ...
- nginx日志分析 GoAccess
也可以生成json:goaccess -q -f web.log -a -p /home/yejianfeng/.goaccessrc -o json >test.json 和csvgoacce ...
- 使用指针来实现变长数组(VLA)
实现代码: #include <cstdio> #include <cstdlib> void usePtoImplementVLA(int SIZE) { scanf(&qu ...
- Composer 安装时要求输入授权用户名密码?
D:\work\dreamland-yii>composer require "saviorlv/yii2-dysms:dev-master" Authentication ...
- 第一次有人把5G讲的这么简单明了
第一次有人把5G讲的这么简单明了 鲜枣课堂 纯洁的微笑 今天 关于5G通信,常见的文章都讲的晦涩难懂,不忍往下看,特转载一篇,用大白话实现5G入门. 简单说,5G就是第五代通信技术,主要特点是波长为毫 ...
- 用标准C编写COM dll
参考资料: 用标准C编写COM(一)COM in plain C,Part1 (http://blog.csdn.net/wangqiulin123456/article/details/809235 ...
- linux:awk修改输出分隔符
file1的内容如下: a b c d e f g h 现在想要修改成 a b c:d e f g:h 则需要用到如下命令: awk -F " " '{print $1,$2,$3 ...
- Qt ------ QFileDialog
QString strFile = QFileDialog::getOpenFileName(this,QStringLiteral("选择Excel文件"),"&quo ...
- 爬虫之requests请求库高级应用
1.SSL Cert Verification #证书验证(大部分网站都是https) import requests respone=requests.get('https://www.12306. ...
- 微信小程序:多张图片上传
最近在写小程序的相册,需要多张图片的上传.因为小程序不支持数组的多张图片同时上传,然后根据自己的需求+借鉴网上各位大神的案例,总算搞定.分享下,不足之处,多多指教哦 页面wxml: <form ...