四十二、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下看的很正 ...
随机推荐
- default.conf
1./etc/nginx/conf.d/ 下设置一个 default.conf,server_name 设置为 localhost,如果有其他非法域名 A 记录到该机器上,则返回默认的 Nginx 页 ...
- 生产者&消费者.py
1.最简单的 --生产者消费者 send.py# !/usr/bin/env python3.5# -*- coding:utf-8 -*-# __author__ == 'LuoTianShuai' ...
- 【mysql】mysql尾部空格
mysql 字段为varchar类型的在查询时候胡忽略尾部空格. 先看表结构 插入一条数据包含空格 在查询是可以查到的 所有在插入数据的时候要对插入字段的数据处理下,php可以用函数trim()去掉两 ...
- 天梯赛 L2-001 紧急救援
L2-001 紧急救援 (25 分) 作为一个城市的应急救援队伍的负责人,你有一张特殊的全国地图.在地图上显示有多个分散的城市和一些连接城市的快速道路.每个城市的救援队数量和每一条连接两个城市的快速道 ...
- C# Winfrom常用的几个公共控件
ComboBox控件的使用方法: //首先写好查询方法,实例化对象, NationData nd = new NationData(); List<Nation> NN = new Lis ...
- postman基于webservice的请求
以 http://ws.webxml.com.cn/WebServices/MobileCodeWS.asmx?op=getMobileCodeInfo 为例 1.先理解事例的内容,请求头和响应 ...
- python 类的介绍
使用面向对象的优点: 1.能够更好的设计软件架构 2.维护软件模块 3.易于架构和组件的重用 类的定义: 构造函数:初始化用,写不写都可以,默认为空 类属性:属于类的对象 方法属性:不属于类的对象 私 ...
- Educational Codeforces Round 55 (Rated for Div. 2) B. Vova and Trophies
传送门 https://www.cnblogs.com/violet-acmer/p/10035971.html 题意: Vova有n个奖杯,这n个奖杯全部是金奖或银奖,Vova将所有奖杯排成一排,你 ...
- Installation failed with message Failed to finalize session: INSTALL_FAILED_TEST_ONLY:installPackageLI.
这样还不行的话,加 -t吧.
- 学习Docker之Dockerfile的命令
使用Dockerfile去构建镜像好比堆积木.使用pom去构建maven项目一样,有异曲同工之妙,下面就把Dockerfile中主要的命令介绍一下. 组成部分 部分 命令 基础镜像信息 FROM 维护 ...