pthread_cond_wait内部逻辑

简单介绍

        引入 pthread_cond_wait 函数的概念,它是 POSIX 线程库中用于条件变量等待的函数。一下是此函数运行时内部逻辑:

1. pthread_cond_wait 函数的调用过程

        描述当程序调用 pthread_cond_wait 函数时会发生什么。包括将执行流放入 PCB 等待队列、解锁等待。

2. 等待被唤醒

        解释在等待被唤醒期间会发生的事情,以及当条件变量满足时,如何唤醒等待线程。

3. 从等待队列中移除

        说明当线程被唤醒后,操作系统如何从 PCB 等待队列中移除线程。

4. 抢占互斥锁

        详细介绍线程在等待结束后,如何尝试抢占互斥锁。

5. 抢占互斥锁的阻塞逻辑

        解释当线程无法立即获得互斥锁时,会发生什么。包括线程被切换出 CPU、上下文信息的保存等。

6. 重新抢占互斥锁

        描述当线程再次获得 CPU 资源后,如何继续抢占互斥锁。

7. 等待结束

        说明当线程最终获得互斥锁时,pthread_cond_wait 函数如何返回。

详解

        条件变量的等待

int pthread_cond_wait(pthread_cond_t *restrict cond,pthread_mutex_t *restrict mutex);
int pthread_cond_timedwait(pthread_cond_t *restrict conpthread_mutex_t *restrict mutex,const struct timespec *restrict abstime);

        为什么这两个接口中有互斥锁?

        条件不会无缘无故地突然变得满足了, 必然会牵扯到共享数据的变化。所以一定要有互斥锁来保护。没有互斥锁, 就无法安全地获取和修改共享数据。

        同步并没有保证互斥,而保证互斥是使用到了互斥锁。

pthread_mutex_lock(&m)
while(condition_is_false)
{pthread_mutex_unlock(&m);//解锁之后, 等待之前, 可能条件已经满足, 信号已经发出, 但是该信号可能会被错过cond_wait(&cv);pthread_mutex_lock(&m);
}

        上面的解锁和等待不是原子操作。解锁以后, 调用cond_wait之前,如果已经有其他线程获取到了互斥量, 并且满足了条件, 同时发出了通知信号, 那么cond_wait将错过这个信号, 可能会导致线程永远处于阻塞状态。所以解锁加等待必须是一个原子性的操作, 以确保已经注册到事件的等待队列之前, 不会有其他线程可以获得互斥量。

        那先注册等待事件, 后释放锁不行吗?注意, 条件等待是个阻塞型的接口, 不单单是注册在事件的等待队列上, 线程也会因此阻塞于此, 从而导致互斥量无法释放, 其他线程获取不到互斥量, 也就无法通过改变共享数据使等待的条件得到满足, 因此这就造成了死锁。

pthread_mutex_lock(&m);
while(condition_is_false)pthread_cond_wait(&v,&m);//此处会阻塞
/*如果代码运行到此处, 则表示我们等待的条件已经满足了,
*并且在此持有了互斥量
*/
/*在满足条件的情况下, 做你想做的事情。
*/
pthread_mutex_unlock(&m);

        pthread_cond_wait函数只能由拥有互斥量的线程来调用, 当该函数返回的时候, 系统会确保该线程再次持有互斥量, 所以这个接口容易给人一种误解, 就是该线程一直在持有互斥量。事实上并不是这样的。这个接口向系统声明了我在PCB等待序列中之后, 就把互斥量给释放了。这样其他线程就有机会持有互斥量,操作共享数据, 触发变化, 使线程等待的条件得到满足。

pthread_cond_wait内部会进行解锁逻辑,则一定要先放到PCB等待序列中,再进行解锁。
while(condition_is_false)pthread_cond_wait(&v,&m);//此处会阻塞
if(condition_is_false)pthread_cond_wait(&v,&m);//此处会阻塞

        唤醒以后, 再次检查条件是否满足, 是不是多此一举?

        因为唤醒中存在虚假唤醒(spurious wakeup) , 换言之,条件尚未满足, pthread_cond_wait就返了。在一些实现中, 即使没有其他线程向条件变量发送信号, 等待此条件变量的线程也有可能会醒来。

        条件满足了发送信号, 但等到调用pthread_cond_wait的线程得到CPU资源时, 条件又再次不满足了。好在无论是哪种情况, 醒来之后再次测试条件是否满足就可以解决虚假等待的问题。

        pthread_cond_wait内部实现逻辑:

  1. 将调用pthread_cond_wait函数的执行流放入到PCB等待队列当中

  2. 解锁

  3. 等待被唤醒

  4. 被唤醒之后:

1、从PCB等待队列中移除出来

2、抢占互斥锁

情况1:拿到互斥锁,pthread_cond_wait就返回了

情况2:没有拿到互斥锁,阻塞在pthread_cond_wait内部抢锁的逻辑中

当阻塞在pthread_cond_wait函数抢锁逻辑中时,一旦执行流时间耗尽,意味着线程就被切换出来了,程序计数器就保存的是抢锁的指令,上下文信息保存的就是寄存器的值

当再次拥有CPU资源后,恢复抢锁逻辑

直到抢锁成功,pthread_cond_wait函数才会返回

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

14:00面试,15:00就出来了,问的问题过于变态了。。。

从小厂出来,没想到在另一家公司又寄了。 到这家公司开始上班,加班是每天必不可少的,看在钱给的比较多的份上,就不太计较了。没想到2月一纸通知,所有人不准加班,加班费不仅没有了,薪资还要降40%…

静态时序分析:典型与非典型时序路径的约束详解(一)

相关阅读 静态时序分析https://blog.csdn.net/weixin_45791458/category_12567571.html?spm1001.2014.3001.5482 时序路径是静态时序分析中的一个重要概念,了解时序路径能帮助设计者更好地编写SDC脚本,本文旨在详细介绍时序路径相关内容。 首先给出时序…

深度Q网络(Deep Q-Network, DQN)

深度Q网络(Deep Q-Network, DQN)是一种结合了深度学习和强化学习的方法,用于解决序列决策问题。它是一种端到端的学习方法,可以直接从原始输入(如像素)中学习如何映射到动作值(即策略),而不需要任何手工特征工程。DQN最初由DeepMind在2015年提出,并在多款Atari 2600游…

代码随想录算法训练营day40|343. 整数拆分、96.不同的二叉搜索树

343. 整数拆分 代码随想录 视频讲解:动态规划,本题关键在于理解递推公式!| LeetCode:343. 整数拆分_哔哩哔哩_bilibili 1.确定dp[i]的含义:正整数i拆分得到的最大乘积 2.确定递推公式:dp[i] max(dp[i], …

Unity角色动画变成半跪\半蹲\下沉 的问题

导入的人物动画发生如图形态 解决方法:找到动画模型,Rig - AnimationType 改为Humanoid ,然后Apply一下

高效加载大文件(pandas+dask)

一、仅用pd加载大文件(iterator、chunksize) 要使用Pandas进行高效加载超大文件,我们通常会利用其内置的分块(chunk)处理功能。不过,请注意,Pandas本身并不支持多线程读取文件;它更倾向于单线程中进行块处理…

千云GPS平台 -在k8s上部署Mysql

构建xtrabackup docker build -t registry.cn-zhangjiakou.aliyuncs.com/qy566/xtrabackup:8.0.34 --rm .部署进度 你可以通过运行以下命令查看启动进度: kubectl get pods -l app=mysql -n mysql-db --watch 测试mysql 发送客户端请求写入数据kubectl run mysql-client --…

解决cs不能生成Linux木马的问题

要解决的问题:众所周知,msf上面的shell或者是其他的shell想反弹给cs默认情况下是只支持windows的,因为cs的监听模块默认没有linux的,但是有些主机就是用linux搭建的,这可怎么办呢。就要用到一个插件CrossC2。 下载插件…

经典算法之桶排序

桶排序(Bucket Sort)是一种将待排序数据分到几个有序的桶里,每个桶里的数据再分别排序的排序算法。桶排序适用于数据分布均匀且范围有限的场景。 概念 桶排序的工作原理是将输入数据分布到有限数量的桶里。每个桶再个别排序(有可能使用其他排序算法)。桶排序不需要比较数…

实操keepalived(高可用)+Nginx(四层代理+七层代理),实现高可用、负载均衡以及动静分离

一 vrrp技术 VRRP 相关术语 VRRP能够在不改变组网的情况下,将多台路由器虚拟成一个虚拟路由器,i通过配置虚拟路由器的IP地址为默认网关,实现网关的备份。 协议版本: VRRPv2 (常用) 和VRRPv3:0 VRRPv2仅适用于IPv4网络,VRRPv3适用…

什么是抖音小店商品卡?商品卡流量怎么做?一篇文章解答清楚!

大家好,我是电商糖果 抖音小店商品卡这个词还是2023年才开始出现的,这对很多不太了解小店的朋友来说,确实是一个新名词。 去年3月份抖音推出了“商品卡免佣”,就是因为这个政策,让商品卡在互联网掀起讨论度。 而今年…

[项目设计] 从零实现的高并发内存池(五)

🌈 博客个人主页:Chris在Coding 🎥 本文所属专栏:[高并发内存池] ❤️ 前置学习专栏:[Linux学习] ⏰ 我们仍在旅途 ​ 目录 8 使用定长内存池脱离new 9. 释放对象时不传大小 10.性能优化 10.1…

[LeetCode][239]【学习日记】滑动窗口最大值——O(n)单调队列

题目 239. 滑动窗口最大值 难度:困难相关标签相关企业提示 给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 返回滑动窗口中的最大值。 示例 1…

雷赛控制卡的扩展IO连接

雷赛控制卡的扩展IO点无法控制问题处理 现象 因设备的上IO点较多,所以使用了多个雷赛32点位的IO扩展卡。上位机程序在控制输出IO时发现主模块IO和第一个扩展IO的输出可以控制。但第二个IO扩展卡和第三个IO扩展卡的输出控制不了。经排查出发现轴卡在初始化时只连接了…

校园小情书微信小程序,社区小程序前后端开源,校园表白墙交友小程序

功能 表白墙卖舍友步数旅行步数排行榜情侣脸漫画脸个人主页私信站内消息今日话题评论点赞收藏 效果图

ROS篇——Debian12通过源码安装ros-noetic

一、先配置sources.list Debian篇——Debian12的sources.list文件配置 二、基本环境部署安装(安装时提示找不到的库,需要修改一下版本 ,安装你能找得到的版本) sudo apt-get install git sudo apt-get install cmake sudo apt-g…

2024年腾讯云学生服务器优惠活动「云+校园」政策解读

2024年腾讯云学生服务器优惠活动「云校园」,学生服务器优惠价格:轻量应用服务器2核2G学生价30元3个月、58元6个月、112元一年,轻量应用服务器4核8G配置191.1元3个月、352.8元6个月、646.8元一年,CVM云服务器2核4G配置842.4元一年&…

几何工具的使用

Geometry - Creation 创建几何 CogCreateCircleTool:创建圆CogCreateEllipseTool:创建椭圆CogCreateLineBisectPointsTool:带有两个点的平行线CogCreateLineParallelTool:在某一点创建某条线的平行线CogCreateLinePerpendicularTool:在某一点创建某条线…

LT6813/ADBMS1818底层驱动---均衡控制

1、LT6813采用内部均衡的原理 2、平衡控制结构体 根据数据库中读取的控制值设置平衡。要为单元设置平衡,必须将相应的位写入配置寄存器中。LTC 驱动程序仅执行数据库中 BMS 写入的数据。 参数 ltc_stateLTC 状态机的状态pSpi接口指向 SPI 配置的指针pTxBuff &…

2024-3-7-网络编程小项目

ser.c #include <myhead.h> #define SER_IP "10.168.1.111" //服务器IP #define SER_PORT 8888 //服务器端口号 struct User {char username[20];struct sockaddr_in cin; }; int main(int argc, const char *argv[]) {struct User ur[1024];//1、创建…