【Linux】< 条件变量等待>解决< 线程饥饿问题 >——【多线程同步问题】

前言

大家好吖,欢迎来到 YY 滴Linux系列 ,热烈欢迎! 本章主要内容面向接触过C++的老铁
主要内容含:
在这里插入图片描述

欢迎订阅 YY滴C++专栏!更多干货持续更新!以下是传送门!

  • YY的《C++》专栏
  • YY的《C++11》专栏
  • YY的《Linux》专栏
  • YY的《数据结构》专栏
  • YY的《C语言基础》专栏
  • YY的《初学者易错点》专栏
  • YY的《小小知识点》专栏
  • YY的《单片机期末速过》专栏
  • YY的《C++期末速过》专栏
  • YY的《单片机》专栏
  • YY的《STM32》专栏
  • YY的《数据库》专栏
  • YY的《数据库原理》专栏

目录

  • 一.<同步>概念&<条件变量>基本概念
  • 二.<条件变量等待> 为什么一定需要 <互斥锁 >?
  • 三.<条件变量>使用规范
  • 四.饥饿问题展示——"直到其他线程改变前,一直处于忙等待"
    • 1.基于【普通队列】的<生产者消费者模型>面临的<线程饥饿问题>
    • 2.基于【阻塞队列】的<生产者消费者模型>解决<线程饥饿问题>
    • 3.<条件变量>实现【阻塞队列】设计部分(图文详细解读)
    • 4.<条件变量>实现【阻塞队列】代码
  • 五.条件变量语法
    • 1.条件变量用到的头文件
    • 2.条件变量的初始化(动态&静态)
    • 3.条件变量的销毁
    • 4.条件变量的等待
    • 5.唤醒(一般是其他线程中)条件变量的等待

一.<同步>概念&<条件变量>基本概念

  • 同步: 在保证数据安全的前提下,让线程能够 按照某种 特定的顺序 访问临界资源 ,从而有效避免 饥饿问题
  • 条件变量: 利用线程间共享的全局变量进行同步的一种机制 它允许一个或多个线程在某个条件满足时进行等待,并在条件满足时被唤醒
  • 注意:条件变量本身不是锁,而是与互斥锁(Mutex)结合使用,以确保线程安全

二.<条件变量等待> 为什么一定需要 <互斥锁 >?

  1. 条件等待是线程间同步的一种手段,如果只有一个线程,条件不满足,一直等下去都不会满足,所以 必须要有一个线程通过某些操作,改变共享变量,使原先不满足的条件变得满足 ,并且友好的通知等待在条件变量上的线程。
  2. 条件不会无缘无故的突然变得满足了,必然会 牵扯到共享数据的变化 所以一定要用互斥锁来保护 。没有互斥锁就无法安全的获取和修改共享数据

三.<条件变量>使用规范

  • 等待条件代码
pthread_mutex_lock(&mutex);
while (条件为假)
     {
     pthread_cond_wait(cond, mutex);
     }
...代码部分
pthread_mutex_unlock(&mutex);
  • 给条件发送信号代码
pthread_mutex_lock(&mutex);

...代码部分改动共享资源,条件变为真
pthread_cond_signal(cond);//给条件发送信号代码
pthread_mutex_unlock(&mutex);

四.饥饿问题展示——“直到其他线程改变前,一直处于忙等待”

1.基于【普通队列】的<生产者消费者模型>面临的<线程饥饿问题>

  • 我们有这样一个场景:
  • 当一个线程 互斥地 访问某个变量时,它可能发现 在其它线程 改变状态 之前,它什么也做不了。
  • 例如:在下面的 生产者消费者(普通队列)模型中 一个线程访问 队列 时,发现队列为空,它 只能等待(忙等待) ,直到其它线程将一个节点添加到队列中
  • 这种情况就需要用到条件变量
    在这里插入图片描述

2.基于【阻塞队列】的<生产者消费者模型>解决<线程饥饿问题>

  • 上面提到: 生产者消费者(普通队列)模型 会面临 <线程饥饿问题>
  • 阻塞队列 则解决了这个问题,用到了 <条件变量>
  • <条件变量> : 条件变量是利用线程间共享的全局变量进行同步的一种机制。它允许一个或多个线程在某个条件满足时进行等待,并在条件满足时被唤醒。条件变量本身不是锁,而是与互斥锁(Mutex)结合使用,以确保线程安全
  • 下面是BlockingQueue的机制:
  • 当队列为空时:从队列获取元素的操作将会被 阻塞,直到队列中被放入了元素;
  • 当队列满时:往队列里存放元素的操作也会被 阻塞,直到有元素被从队列中取出
  • 多线程编程中阻塞队列(Blocking Queue) 解决了 <线程饥饿问题>
    在这里插入图片描述

3.<条件变量>实现【阻塞队列】设计部分(图文详细解读)

  • 我们如图所示,在入队列和出队列处分别设置 互斥量(锁) 条件变量(锁)
    在这里插入图片描述

我们拿线程1入队列过程举例:

  • 队列满了,在1号条件变量上等待;
  • 队列空了,在2号条件变量上等待
  1. 线程1生产资源进入队列,上互斥锁,发现不符合1号条件变量的条件(队列没满),程序往下跑,解除互斥锁
  2. 线程1生产资源进入队列,上互斥锁, 发现符合1号条件变量(队列满了),在条件变量上等待 ,程序不往下跑
  3. 此时,线程2消费资源出队列,上互斥锁,发现符合2号条件变量(队列非空),程序往下跑,解除互斥锁; 此时给1号线程条件变量发送信号,唤醒1号条件变量,告诉他“ 你不用等了 ”
  4. 此时线程1的条件变量被唤醒,程序往下跑,解除互斥锁

4.<条件变量>实现【阻塞队列】代码

  • 回顾阻塞队列:
  • 注:这里很多条件变量函数我们还没有介绍,我们明白其作用即可 ,会放到博客最后
  • 当队列为空时:从队列获取元素的操作将会被 阻塞,直到队列中被放入了元素;
  • 当队列满时:往队列里存放元素的操作也会被 阻塞,直到有元素被从队列中取出
  • 代码实现如下:
  • 只展示出入队列部分,完整版本在最后

//_c_cond消费者consumer的条件变量
//_p_cond生产者productor的条件变量
//_q是阻塞队列

void Push(const T &in)//生产者productor
{
     pthread_mutex_lock(&_mutex);
     if(IsFull())//判断是否满,满了进入阻塞等待
     {
     //自己,阻塞等待
     pthread_cond_wait(&_p_cond,&_mutex);
     }

     _q.push(in);//生产
     
     //生产了,另一个线程条件变量不符合了,唤醒另一个线程的条件变量阻塞等待
     pthread_cond_signal(&_c_cond);
     pthread_mutex_unlock(&_mutex);
}

void Pop(T *out)//消费者consumer
{
     pthread_mutex_lock(&_mutex);
     if(IsEmpty())//判断是否空,空了进入阻塞等待
     {
     //自己,阻塞等待
     pthread_cond_wait(&_c_cond,&_mutex);//伪唤醒状态
     }
     
     *out=_q.front();
     _q.pop();//消费
     
     //消费了,另一个线程条件变量不符合了,唤醒另一个线程的条件变量阻塞等待
     pthread_cond_signal(&_p_cond);
     pthread_mutex_unlock(&_mutex);
}

五.条件变量语法

1.条件变量用到的头文件

  • 线程库中有 互斥锁 和 条件变量
#include <stdio.h>  
#include <pthread.h> 

2.条件变量的初始化(动态&静态)

初始化条件变量有两种方法:静态初始化和动态初始化

  • 方法1, 静态初始化:
  • 静态初始化的互斥量 不需要 显式调用pthread_cond_destroy函数进行销毁
pthread_cond_t cond_d = PTHREAD_COND_INITIALIZER;
  • 方法2, 动态初始化:
  • 动态初始化的条件变量在使用完毕后需要显式调用pthread_cond_destroy函数进行销毁
pthread_cond_t cond;
int pthread_cond_init(pthread_cond_t *restrict cond,const pthread_condattr_t *restrict attr);
参数:
    cond:要初始化的条件变量
    attr:条件变量使用的属性对象,通常传递NULL表示使用默认属性。

3.条件变量的销毁

  • 动态初始化的条件变量在使用完毕后需要显式调用pthread_cond_destroy函数进行销毁
int pthread_cond_destroy(pthread_cond_t *cond);
返回值:
     
	int ret = pthread_cond_destroy(&cond_d);  
	if (ret != 0) {  
	    fprintf(stderr, "Failed to destroy condition variable: %s\n", strerror(ret));  
	    exit(EXIT_FAILURE);  
	}

4.条件变量的等待

int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
参数:
    cond:要在这个条件变量上等待
    mutex:互斥量

5.唤醒(一般是其他线程中)条件变量的等待

int pthread_cond_broadcast(pthread_cond_t *cond);
int pthread_cond_signal(pthread_cond_t *cond);

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/895488.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

php生成PDF文件(FPDF)

FPDF即“Free PDF”&#xff0c;FPDF类库提供了基本的PDF创建功能&#xff0c;其源代码和使用权是免费的。 PDF格式文档优势 通用&#xff1a;PDF文档在UNIX和Windows系统均可正常使用。 安全&#xff1a;PDF文档可设置为只读模式&#xff0c;并且可以添加密码等保护措施。 美…

即使是编程新手,也能利用ChatGPT编写高质量的EA

在外汇交易领域&#xff0c;MetaTrader是一款备受欢迎的交易软件&#xff0c;包括MT5和MT4&#xff0c;提供了众多强大的分析工具和自动化交易功能。对于没有编程经验的新手而言&#xff0c;编写专家顾问&#xff08;EA&#xff09;可能显得既复杂又令人望而却步。幸运的是&…

SpringCloudAlibaba[Nacos]注册配置中心注册与发现服务

Nacos的全称是Dynamic Naming and Configuration Service&#xff0c;Na为naming/nameServer即注册中心,co为configuration即注册中心&#xff0c;service是指该注册/配置中心都是以服务为核心。是阿里巴巴开源易于构建云原生应用的动态服务发现、配置管理和服务管理平台。 Nac…

Django安装中遇到的问题

虚拟环境中应该使用 python -m pip 2.这里是runserver

软体机器人纤维:材料选择有讲究,热拉伸工艺来制造,多种功能应用

大家好&#xff01;今天我们来了解 “用于软体机器人的高度集成多材料纤维” 这一研究——《Highly Integrated Multi‐Material Fibers for Soft Robotics》发表于《Advanced Science》。软体机器人在医疗等领域潜力巨大&#xff0c;但传统制造技术存在局限。本研究聚焦热拉伸…

Kafka之消费者组与消费者

消费者&#xff08;Consumer&#xff09;在Kafka的体系结构中是用来负责订阅Kafka中的主题&#xff08;Topic&#xff09;&#xff0c;并从订阅的主题中拉取消息后进行处理。 与其他消息中间件不同&#xff0c;Kafka引入一个逻辑概念——消费组&#xff08;Consumer Group&…

WPF实现类似网易云音乐的菜单切换

这里是借助三方UI框架实现了&#xff0c;感兴趣的小伙伴可以看一下。 深色模式&#xff1a;​ 浅色模式&#xff1a; ​这里主要使用了以下三个包&#xff1a; MahApps.Metro&#xff1a;UI库&#xff0c;提供菜单导航和其它控件​​​​​​​ 实现步骤&#xff1a;1、使用B…

【含文档】基于Springboot+Vue的二手书籍交易系统(含源码+数据库+lw)

1.开发环境 开发系统:Windows10/11 架构模式:MVC/前后端分离 JDK版本: Java JDK1.8 开发工具:IDEA 数据库版本: mysql5.7或8.0 数据库可视化工具: navicat 服务器: SpringBoot自带 apache tomcat 主要技术: Java,Springboot,mybatis,mysql,vue 2.视频演示地址 3.功能 系统定…

博流bl616开发笔记

本文大体框架如图 目录 一、博流BL616、BL618基本框架、信息二、博流烧录环境搭建1. Windows环境1.1 SDK1.2 编译工具链1.3 开发工具1.4 程序编译下载1.4.1 eclipse使用步骤1.4.2 vscode使用步骤 2. Linux环境 三、基本外设使用前言1.GPIO1.1 硬件原理图1.2 API1.2.1句柄1.2.2…

3d NMDS多样性分析图 R语言

# 安装并加载必要的包 if (!require("vegan")) install.packages("vegan") if (!require("ggplot2")) install.packages("ggplot2") if (!require("plotly")) install.packages("plotly") if (!require("ret…

code CERT_HAS_EXPIRED npm ERR! errno CERT_HAS_EXPIRED 证书过期

解决方案&#xff1a; 1、以管理员权限打开cmd 2、 若项目在D盘,先换成D: 3、cd进入项目路径 4、清空缓存 npm cache clean --force 5、查看当前的npm镜像设置 npm config get registry 6、切换新源 npm config set registry https://registry.npmmirror.com 7、查看新源…

六大知名Web安全漏洞靶场

如果想搞懂一个漏洞&#xff0c;最好的方法是先编写出这个漏洞&#xff0c;然后利用它&#xff0c;最后修复它。漏洞靶场模拟真实环境&#xff0c;它为网络安全人员提供了一个安全可控的平台&#xff0c;用于发现、评估和测试应用程序、系统或网络设备的安全漏洞。WEB漏洞靶场可…

【Linux】如何通过系统宏定义,获取进程的退出码或退出信号

我们可以通过系统写好的宏来获取获取进程的退出码或退出信号&#xff1a;底层是通过对 waitpid 函数参数 status 进行位运算&#xff0c;取对应部分的数值 一、相关宏定义的介绍 waitpid(pid, &status, 0);&#xff1a; 这行代码等待指定 PID (pid) 的子进程结束&#x…

linux环境下C程序的编译过程以及makefile的简单使用

在windows下&#xff0c;很多用来进行编程软件对于写好的文件&#xff0c;点击编译即可生成想要文件。如.exe可执行文件&#xff0c;.hex文件或者.bin文件等等。软件为我们省略了很多事。但是对于linux初学者来说&#xff0c;初次接触linux系统&#xff0c;面对命令行黑框框有点…

Java后端面试题:MySQL篇

目录 MySQL基础部分 1. SELECT语句完整的执行顺序是什么&#xff1f; 2. 说一说内连接和外连接。 3. 请说说数据库三大范式。 4. 请你说说视图的作用&#xff0c;视图可以更改么&#xff1f; 架构 5. 请你说一说MySQL架构。 6. 请你说说一条SQL语句的执行过程&#xff…

MIT 6.5840(6.824) Lab 5:Sharded Key/Value Service 设计实现

文章目录 1 实验要求1.1 介绍1.2 lab5A&#xff1a;控制器和静态分片1.3 lab5B&#xff1a;碎片移动1.4 挑战任务 2 实验设计2.1 整体架构2.2 shardctrler2.3 shardkv server2.3.1 结构2.3.2 日志类型2.3.3 读写服务2.3.4 配置更新检测2.3.5 分片迁移2.3.6 垃圾回收2.3.7 空日志…

一个简单的Qt Console Application计算练习程序

初步体验Qt Creator 用途&#xff1a;练习20以内2位数乘法速算的程序 功能1&#xff1a;支持用户设定题目数量 std::cout << "请输入本次练习题目数量&#xff1a;";int numProblems 0;std::string num;std::cin >> num;try {numProblems std::stoi(…

【云从】六、云存储

文章目录 1、应用架构2、存储设备3、存储方案3.1 直连式存储DAS3.2 网络连接存储NAS3.3 存储区域网络SAN3.4 分布式存储ServerSAN3.5 软件定义存储SDS 4、云存储4.1 云硬盘CBS4.2 文件存储CFS4.3 对象存储COS 1、应用架构 2、存储设备 硬盘性能对比&#xff1a; 硬盘接口对比&…

ubuntu docker安装elasticsearch:7.12.1

#es和kibana容器互联网络 docker network create es-netdocker pull elasticsearch:7.12.1 docker pull kibana:7.12.1 mkdir -p /root/datas/docker/es/data mkdir -p /root/datas/docker/es/logs mkdir -p /root/datas/docker/es/pluginssudo chmod -R 777 /root/datas/docke…

高级算法设计与分析 学习笔记13 线性规划

注意是线性规划不是动态规划哦 好家伙&#xff0c;这不是凸优化吗&#xff1f; 凸优化标准形式&#xff1a; 先改成统一最大化&#xff08;凸优化那边怎么是统一最小化&#xff1f;&#xff09; 原来的x2正负无所谓&#xff0c;但我希望每个x都是有限制的&#xff0c;所以把它改…