pthread_cond_wait内部逻辑

2024-03-07 23:44
文章标签 逻辑 内部 wait pthread cond

本文主要是介绍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函数才会返回

这篇关于pthread_cond_wait内部逻辑的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/785239

相关文章

STM32内部闪存FLASH(内部ROM)、IAP

1 FLASH简介  1 利用程序存储器的剩余空间来保存掉电不丢失的用户数据 2 通过在程序中编程(IAP)实现程序的自我更新 (OTA) 3在线编程(ICP把整个程序都更新掉) 1 系统的Bootloader写死了,只能用串口下载到指定的位置,启动方式也不方便需要配置BOOT引脚触发启动  4 IAP(自己写的Bootloader,实现程序升级) 1 比如蓝牙转串口,

FreeRTOS内部机制学习03(事件组内部机制)

文章目录 事件组使用的场景事件组的核心以及Set事件API做的事情事件组的特殊之处事件组为什么不关闭中断xEventGroupSetBitsFromISR内部是怎么做的? 事件组使用的场景 学校组织秋游,组长在等待: 张三:我到了 李四:我到了 王五:我到了 组长说:好,大家都到齐了,出发! 秋游回来第二天就要提交一篇心得报告,组长在焦急等待:张三、李四、王五谁先写好就交谁的

linux 下Time_wait过多问题解决

转自:http://blog.csdn.net/jaylong35/article/details/6605077 问题起因: 自己开发了一个服务器和客户端,通过短连接的方式来进行通讯,由于过于频繁的创建连接,导致系统连接数量被占用,不能及时释放。看了一下18888,当时吓到了。 现象: 1、外部机器不能正常连接SSH 2、内向外不能够正常的ping通过,域名也不能正常解析。

java线程深度解析(一)——java new 接口?匿名内部类给你答案

http://blog.csdn.net/daybreak1209/article/details/51305477 一、内部类 1、内部类初识 一般,一个类里主要包含类的方法和属性,但在Java中还提出在类中继续定义类(内部类)的概念。 内部类的定义:类的内部定义类 先来看一个实例 [html]  view plain copy pu

逻辑表达式,最小项

目录 得到此图的逻辑电路 1.画出它的真值表 2.根据真值表写出逻辑式 3.画逻辑图 逻辑函数的表示 逻辑表达式 最小项 定义 基本性质 最小项编号 最小项表达式   得到此图的逻辑电路 1.画出它的真值表 这是同或的逻辑式。 2.根据真值表写出逻辑式   3.画逻辑图   有两种画法,1是根据运算优先级非>与>或得到,第二种是采

UMI复现代码运行逻辑全流程(一)——eval_real.py(尚在更新)

一、文件夹功能解析 全文件夹如下 其中,核心文件作用为: diffusion_policy:扩散策略核心文件夹,包含了众多模型及基础库 example:标定及配置文件 scripts/scripts_real:测试脚本文件,区别在于前者倾向于单体运行,后者为整体运行 scripts_slam_pipeline:orb_slam3运行全部文件 umi:核心交互文件夹,作用在于构建真

一次生产环境大量CLOSE_WAIT导致服务无法访问的定位过程

1.症状 生产环境的一个服务突然无法访问,服务的交互过程如下所示: 所有的请求都是通过网关进入,之后分发到后端服务。 现在的情况是用户服务无法访问商旅服务,网关有大量java.net.SocketTimeoutException: Read timed out报错日志,商旅服务也不断有日志打印,大多是回调和定时任务日志,所以故障点在网关和商旅服务,大概率是商旅服务无法访问导致网关超时。 后

Java基础入门 【第七章 抽象、接口、内部类、枚举】(二)

匿名内部类书写格式: 父类或接口类型变量名=new父类或接口(构造方法实参列表){ //重写所有的抽象方法 @Override public返回值类型method1(形参列表){ 方法体实现 } @Override public返回值类型method2(形参列表){ 方法体实现 } //省略... }; //匿名内部类对象调用方法 变量名.重写方法(实参列表); 匿名

(六十四)第 10 章 内部排序(静态链表的插入排序)

示例代码 staticLinkList.h // 静态链表的插入排序实现头文件#ifndef STATIC_LINK_LIST_H#define STATIC_LINK_LIST_H#include "errorRecord.h"#define SIZE 100#define NUM 8typedef int InfoType;typedef int KeyType;ty

selenium的webdriver三种等待方式(显式等待WebDriverWait+implicitly_wait隐式等待+sleep强制等待)

隐式等待是等页面加载,不是等元素!!! 1、显式等待  一个显式等待是你定义的一段代码,用于等待某个条件发生然后再继续执行后续代码。显式等待是等元素加载!!! from selenium import webdriverfrom selenium.webdriver.common.by import Byfrom selenium.webdriver.support.ui import