线程与进程深度解析:从fork行为到生产者-消费者模型
线程与进程深度解析:从fork行为到生产者-消费者模型
一、多线程环境下的fork行为与线程安全
1. 多线程程序中fork的特殊性
核心问题:fork后子进程的线程模型
当多线程程序中的某个线程调用fork
时:
- 子进程仅包含调用fork的线程:子进程是调用fork线程的完整复刻,其他线程不会被复制。父进程的所有线程状态(如寄存器值、栈数据)会被复制,但子进程仅以单线程形式运行。
- 锁状态的继承风险:子进程会继承父进程中互斥锁、条件变量等同步对象的状态。若父进程中锁处于加锁状态,子进程会继承该状态,可能导致死锁(子进程无法释放父进程的锁)。
示例场景:
父进程有线程A(持有锁)和线程B,线程B调用fork:
- 子进程仅有线程B的副本,且继承锁的加锁状态。
- 若子进程后续尝试加锁,会因锁已被占用而阻塞,引发死锁。
思考问题1:
为什么fork后子进程不复制所有线程?
答:fork设计初衷是复制进程而非线程,线程是进程内的执行流。复制所有线程会增加复杂度(如线程间同步状态难以处理),因此POSIX标准规定fork后子进程仅保留调用线程。
2. pthread_atfork:fork前后的锁状态管理
为解决锁状态继承问题,pthread提供pthread_atfork
函数,允许注册三个回调函数控制fork前后的锁操作:
int pthread_atfork(void (*prepare)(void), // fork前执行(释放所有锁)void (*parent)(void), // fork后父进程执行(重新获取锁)void (*child)(void) // fork后子进程执行(重置锁状态)
);
核心逻辑:
- prepare阶段:释放父进程所有锁,避免子进程继承加锁状态。
- parent阶段:父进程重新获取锁,恢复正常执行。
- child阶段:子进程重置锁(如重新初始化或释放),确保独立状态。
示例代码解析:
void prepare() { pthread_mutex_unlock(&mutex); } // fork前释放锁
void parent() { pthread_mutex_lock(&mutex); } // 父进程重新加锁
void child() { pthread_mutex_unlock(&mutex); } // 子进程释放(避免继承加锁状态)pthread_atfork(prepare, parent, child); // 注册回调
思考问题2:
若未使用pthread_atfork,子进程能否安全使用父进程的锁?
答:不能。锁状态被复制但独立,父进程释放锁不会影响子进程,可能导致子进程持有无效锁状态,引发竞态条件或死锁。
二、多线程中的多生产者-多消费者模型:基于信号量的高效同步
1. 模型核心思想
通过缓冲区解耦生产者与消费者,利用同步机制确保:
- 生产者不向满缓冲区写数据
- 消费者不从空缓冲区读数据
2. 关键组件:
组件 | 作用 | 实现方式 |
---|---|---|
缓冲区 | 暂存数据(环形队列) | 固定大小数组,索引取模实现循环 |
同步机制 | 控制缓冲区访问(互斥+信号量) | 互斥锁(mutex)+ 计数信号量 |
信号量 | 计数空槽(empty)和满槽(full) | sem_init初始化,sem_wait/sem_post操作 |
3. 代码实现详解
#define BUFFSIZE 30 // 缓冲区大小
int buff[BUFFSIZE]; // 环形缓冲区
int in = 0, out = 0; // 读写索引sem_t empty, full; // 空槽数(初始=BUFFSIZE)、满槽数(初始=0)
pthread_mutex_t mutex; // 互斥锁保护缓冲区// 生产者线程函数
void* Product_fun(void *arg) {int index = (int)arg;for (int i = 0; i < 30; i++) {sem_wait(&empty); // 等待空槽pthread_mutex_lock(&mutex); // 互斥访问缓冲区buff[in] = rand() % 100; // 写入数据printf("生产者%d写入:位置%d,数值%d\n", index, in, buff[in]);in = (in + 1) % BUFFSIZE; // 索引循环pthread_mutex_unlock(&mutex);sem_post(&full); // 满槽数+1sleep(rand()%5); // 模拟生产耗时}return NULL;
}// 消费者线程函数
void* Customer_fun(void *arg) {int index = (int)arg;for (int i = 0; i < 20; i++) {sem_wait(&full); // 等待满槽pthread_mutex_lock(&mutex);printf("消费者%d读取:位置%d,数值%d\n", index, out, buff[out]);out = (out + 1) % BUFFSIZE; // 索引循环pthread_mutex_unlock(&mutex);sem_post(&empty); // 空槽数+1sleep(rand()%5); // 模拟消费耗时}return NULL;
}
同步逻辑解析:
- 信号量分工:
empty
信号量控制生产者:每次生产前sem_wait
(空槽数-1),生产后sem_post
(满槽数+1)。full
信号量控制消费者:每次消费前sem_wait
(满槽数-1),消费后sem_post
(空槽数+1)。
- 互斥锁作用:确保缓冲区索引
in/out
的修改是原子操作,避免多生产者/消费者同时修改索引导致数据混乱。
4. 常见问题与优化
思考问题3:
为什么同时使用信号量和互斥锁?
答:
- 信号量解决“缓冲区是否可读写”的宏观控制(空/满槽计数)。
- 互斥锁解决“缓冲区具体位置读写”的微观互斥(避免多个线程同时修改
in/out
索引)。
二者结合实现“计数同步+互斥访问”的完整控制。
思考问题4:
如何处理缓冲区溢出?
答:
- 环形缓冲区通过索引取模(
in = (in+1)%BUFFSIZE
)自然处理溢出,无需额外判断。 - 信号量
empty
和full
确保只有在缓冲区非满/非空时才允许读写,从源头避免溢出。
思考问题5:
生产者-消费者模型的变种有哪些?
答:
- 单生产者-单消费者:无需互斥锁,仅用信号量即可(索引修改无需竞争)。
- 多生产者-多消费者:必须用互斥锁保护共享索引,如示例代码所示。
- 有界缓冲区 vs 无界缓冲区:无界缓冲区无需
full
信号量,但需处理内存动态分配(如链表实现)。
三、最佳实践与陷阱规避
1. fork场景最佳实践
- 限制fork使用:多线程程序中尽量避免调用fork,若必须使用,通过
pthread_atfork
清理锁状态。 - 子进程逻辑简化:fork后子进程尽快调用exec系列函数,重置程序状态,避免依赖父进程的同步对象。
2. 生产者-消费者调优技巧
- 缓冲区大小权衡:根据生产/消费速度动态调整
BUFFSIZE
,过大导致内存浪费,过小导致频繁等待。 - 减少锁持有时间:将非必要操作(如数据计算)移到临界区外,提高并发效率。
3. 死锁预防策略
- 信号量顺序固定:始终先获取信号量(
sem_wait
)后获取互斥锁,避免顺序混乱导致循环等待。 - 超时机制:使用
sem_timedwait
或pthread_mutex_timedlock
,避免无限阻塞。
总结
多线程与fork的交互需要关注锁状态的继承问题,通过pthread_atfork
确保同步对象的正确初始化。生产者-消费者模型则是同步机制的经典应用,通过信号量与互斥锁的配合,实现高效的并发数据处理。理解这些机制的底层逻辑和适用场景,是解决多线程编程中复杂问题的关键。
相关文章:
线程与进程深度解析:从fork行为到生产者-消费者模型
线程与进程深度解析:从fork行为到生产者-消费者模型 一、多线程环境下的fork行为与线程安全 1. 多线程程序中fork的特殊性 核心问题:fork后子进程的线程模型 当多线程程序中的某个线程调用fork时: 子进程仅包含调用fork的线程࿱…...
2025年第十六届蓝桥杯省赛B组Java题解【完整、易懂版】
2025年第十六届蓝桥杯省赛B组Java题解 题型概览与整体分析 题目编号题目名称题型难度核心知识点通过率(预估)A逃离高塔结果填空★☆☆数学规律、模运算95%B消失的蓝宝结果填空★★★同余定理、中国剩余定理45%C电池分组编程题★★☆异或运算性质70%D魔法…...
【NTN 卫星通信】NTN关键问题的一些解决方法(一)
1 概述 3GPP在协议23.737中对一些卫星通信需要面对的关键问题进行了探讨,并且讨论了初步的解决方法,继续来看看这些内容把。 问题包括: 1、大型卫星覆盖区域的移动性管理 2、移动卫星覆盖区域的移动性管理 3、卫星延迟 4、卫星接入的QoS …...
C++基础算法9:Dijkstra
1、概念 Dijkstra算法 是一种用于计算图中单源最短路径的算法,主要用于加权图(图中边的权重可以不同)中找出从起点到各个其他节点的最短路径。 Dijkstra算法的核心概念: 图的表示: 有向图:图的边是有方…...
5块钱的无忧套餐卡可以变成流量卡吗
电信的 5 块钱无忧套餐卡理论上可以变成流量卡,但会受到一些条件限制,以下是具体介绍: 中国电信无忧卡简介 中国电信无忧卡是电信推出的低月租套餐,月租仅 5 元,包含 200M 国内流量、来电显示和 189 邮箱,全…...
word页眉去掉线
直接双击页眉处于下面状态: 然后: 按CtrlshiftN即可!去除...
Spark,Idea中编写Spark程序 2
Idea中编写Spark程序 一、修改pom.xml文件 <build><sourceDirectory>src/main/scala</sourceDirectory><testSourceDirectory>src/test/scala</testSourceDirectory> <!-- 添加必要的插件以打包scala程序--><plugins><plu…...
GTID(全局事务标识符)的深入解析
GTID(全局事务标识符)的深入解析 GTID(Global Transaction Identifier)是 MySQL 5.6 版本引入的一项核心功能,旨在解决传统主从复制中的痛点。它通过为每个事务赋予一个全局唯一的标识符,彻底改变了复制的管理方式。 一、传统复制的痛点 在 GTID 出现之前,MySQL 主从…...
Circular Plot系列(一): 环形热图绘制
针对近期多个粉丝咨询环形图的绘制,我意识到,我们似乎没有真正介绍过circle图,但这一类图确是非常常用的图,所以这里详细学习一下circle的绘制,使用的是circlize包,功能很完善:安装包, #https:/…...
字符串匹配 之 KMP算法
文章目录 习题28.找出字符串中第一个匹配项的下标1392.最长快乐前缀 本博客充分参考灵神和知乎的另一位博主 灵神KMP算法模版 知乎博主通俗易懂讲解 对于给定一个主串S和一个模式串P,如果让你求解出模式串P在主串S中匹配的情况下的所有的开始下标简单的做法又称为Brute-Force算…...
「一针见血能力」的终极训练手册
缘起 和顶尖的高手接触以后,发现他们在表达沟通上面的能力真的太强了,仿佛有种一阵见血看问题的能力,这种拨开浓雾看本质的能力是嘈杂世界防止上当受骗的不二法门. 网上找了一些训练方法,可以试试训练锐化思维,提高表…...
Linux 入门:操作系统进程详解
目录 一.冯诺依曼体系结构 一). 软件运行前为什么要先加载?程序运行之前在哪里? 二).理解数据流动 二.操作系统OS(Operator System) 一).概念 二).设计OS的目的 三).如何理解操作系统…...
【2025软考高级架构师】——2024年05月份真题与解析
摘要 本文内容是关于2025年软考高级架构师考试的相关资料,包含2024年05月份真题与解析。其中涉及体系结构演化的步骤、OSI协议中能提供安全服务的层次、数据库设计阶段中进行关系反规范化的环节等知识点,还提及了软考高级架构师考试的多个模块ÿ…...
Mybatis执行流程知多少
思维导图: 一、MyBatis 执行流程概述 MyBatis 的执行流程可以大致分为以下几个关键步骤:配置加载、会话创建、SQL 执行和结果处理。下面我们将逐步详细介绍每个步骤。 二、配置加载 1. 配置文件的重要性 MyBatis 的配置文件是整个框架的基础,…...
码蹄集——偶数位、四边形坐标
目录 MT1039 偶数位 MT1051 四边形坐标 MT1039 偶数位 思路:直接使用按位操作符 一个整型数字是32位,十六进制表示为0x后跟8个字符,每个字符为0-e,代表0-15; 把偶数位改为0,就是用0去&偶数位,用1去&奇数位,即0xAAAAAAAA,A代表10,1010(从右往 左依次为0位,…...
Java 中使用 Callable 创建线程的方法
一、Callable 接口概述 Callable接口位于java.util.concurrent包中,与Runnable接口类似,同样用于定义线程执行的任务,但它具有以下独特特性: 支持返回值:Callable接口声明了一个call()方法,该方法会在…...
代码随想录算法训练营Day44
力扣1045.不相交的线【medium】 力扣53.最大子数组和【medium】 力扣392.判断子序列【easy】 一、力扣1045.不相交的线【medium】 题目链接:力扣1045.不相交的线 视频链接:代码随想录 题解链接:灵茶山艾府 1、思路 和1143.最长公共子序列一…...
Java大师成长计划之第12天:性能调优与GC原理
📢 友情提示: 本文由银河易创AI(https://ai.eaigx.com)平台gpt-4o-mini模型辅助创作完成,旨在提供灵感参考与技术分享,文中关键数据、代码与结论建议通过官方渠道验证。 在 Java 编程中,性能调优…...
【MySQL】索引(重要)
目录 一、索引本质: 索引的核心作用 索引的优缺点 二、预备知识: 硬件理解: 软件理解: MySQL与磁盘交互基本单位: 三、索引的理解: 理解page: 单个page: 多个page&#x…...
C++多态(上)
目录 一、多态的概念 二、多态的定义及实现 1. 多态的构成条件 2. 虚函数 3. 虚函数的重写 4. C11 override 和 final 4.1 final 关键字 4.2 override 关键字 5. 重载、覆盖(重写)、隐藏(重定义)的对比 三、抽象类 1. 概…...
【AI提示词】 复利效应教育专家
提示说明 一位拥有金融学和教育学背景的知识型内容创作者,擅长用简单易懂的语言向读者解释复杂概念 提示词 # Role: 复利效应教育专家## Profile - language: 中文 - description: 一位拥有金融学和教育学背景的知识型内容创作者,擅长用简单易懂的语言…...
嵌入式系统基础知识
目录 一、冯诺依曼结构与哈佛结构 (一)冯诺依曼结构 (二)哈佛架构 二、ARM存储模式 (一)大端模式 (二)小端模式 (三)混合模式 三、CISC 与 RISC &am…...
如何克服情绪拖延症?
引言 你是否也曾有过这样的经历? 明明手头有重要的工作,却总是忍不住刷手机、看视频,直到最后一刻才匆忙赶工? 你是否在心里暗暗发誓“明天一定好好干”,但第二天依旧重复着同样的拖延? 其实࿰…...
【操作系统】哲学家进餐问题
问题描述 哲学家进餐问题是并发编程中的一个经典问题,描述了五位哲学家围坐在一张圆桌旁,他们的生活由思考和进餐组成。在圆桌上有五个盘子,每位哲学家面前一个盘子,盘子之间有一支叉子。哲学家进餐需要同时使用左右两支叉子。问题…...
Kotlin协程解析
目录 一、协程的使用 二、协程的执行原理 2.1、挂起函数的反编译代码及执行分析 2.2、协程执行流程分析 2.2.1、createCoroutineUnintercepted方法 2.2.2、intercepted方法 2.2.3、resumeCancellableWith方法 2.3、Dispatcher----分发器的实现 2.3.1、Main 分发器的实…...
Nginx核心功能 02
目录 Nginx代理技术核心概念 (一)正向代理(Forward Proxy) 1. 基本定义 2. 技术原理 3. 应用场景 (二)反向代理(Reverse Proxy) 1. 基本定义 2. 技术原理 3. 应用场景 一、…...
聊聊对Mysql的理解
目录 1、Sql介绍 1.1、SQL的分类 1.2、数据库的三大范式 1.3、数据表的约束 1.4、约束的添加与删除 2、核心特性 3、主要组件 4、数据结构原理 5、索引失效 6、常用问题 7、优势与局限 前言 MySQL是一个开源的关系型数据库管理系统(RDBMS),由瑞典MySQL A…...
「Mac畅玩AIGC与多模态17」开发篇13 - 条件判断与分支跳转工作流示例
一、概述 本篇在多节点串联的基础上,进一步引入条件判断与分支跳转机制,实现根据用户输入内容动态走不同执行路径。开发人员将学习如何配置判断节点、定义分支规则,以及如何在工作流中引导执行方向,完成基础的逻辑控制。 二、环境准备 macOS 系统Dify 平台已部署并可访问…...
pycharm terminal 窗口打不开了
参考添加链接描述powershell.exe改为cmd.exe发现有一个小正方形,最大化可以看见了。...
JAVA:使用 MapStruct 实现高效对象映射的技术指南
1、简述 在 Java 开发中,对象之间的转换是一个常见的需求,尤其是在 DTO(数据传输对象)和实体类之间的转换过程中。手动编写转换代码既耗时又容易出错,而 MapStruct 是一个优秀的对象映射框架,可以通过注解生成高效的对象转换代码,从而大大提升开发效率。 本文将介绍 M…...
Linux线程深度解析:从基础到实践
Linux线程深度解析:从基础到实践 一、线程基础概念 1. 进程与线程定义 进程:一个正在运行的程序,是操作系统资源分配的最小单位(拥有独立的地址空间、文件描述符等资源),状态包括就绪、运行、阻塞。线程…...
【ROS2】launch启动文件如何集成到ROS2(Python版本)
一、简单实操 1.创建/打开一个功能包 mkdir -p my_ws/src cd my_ws/src ros2 pkg create my_pkg_example --build-type ament_python 2.创建Launch文件的存放目录 将所有启动文件都存储在launch包内的目录中。 目录结构如下所示: src/my_pkg_example/launch/…...
用 PyTorch 轻松实现 MNIST 手写数字识别
用 PyTorch 轻松实现 MNIST 手写数字识别 引言 在深度学习领域,MNIST 数据集就像是 “Hello World” 级别的经典入门项目。它包含大量手写数字图像及对应标签,非常适合新手学习如何搭建和训练神经网络模型。本文将基于 PyTorch 框架,详细拆…...
碰撞检测学习笔记
目录 SUMO 模拟碰撞 LimSim pygame模拟碰撞检测 SUMO 模拟碰撞 LimSim 多模态大语言模型(M)LLM的出现为人工智能开辟了新的途径,特别是提供增强的理解和推理能力,为自动驾驶开辟了新途径。本文介绍LimSim,LimSim的…...
Sway初体验
Sway(缩写自 SirCmpwn’s Wayland compositor[1])是一款专为 Wayland 设计的合成器,旨在与 i3 完全兼容。根据官网所述: Sway 是 Wayland 的合成器,也是 x11 的 i3 窗口管理器的替代品。它可以根据您现有的 i3 配置工作…...
《工业社会的诞生》章节
工业革命的技术前奏 早期工业技术双引擎: 【火药武器】:重塑战争形态与经济地理 新式青铜炮助力殖民扩张,开辟全球贸易网络 高桅帆船(西班牙大帆船)实现洲际航行 战争规模化倒逼中央集权,催生国家-商人…...
消息队列MQ
参考资料:https://cloud.tencent.com/developer/article/2335397 https://www.cnblogs.com/hahaha111122222/p/18457859 消息队列是大型分布式系统不可缺少的中间件,也是高并发系统的基石中间件 消息队列 消息队列 Message Queue 消息队列是利用高效可…...
LangChain4J-XiaozhiAI 项目分析报告
LangChain4J-XiaozhiAI 项目分析报告 GitHub 链接 1. 项目概述 本项目名为 “硅谷小智(医疗版)”,是一个基于 Java 技术栈和 LangChain4J 框架构建的 AI 聊天助手应用。其核心目标是利用大型语言模型(LLM)的能力&am…...
学习spring boot-拦截器Interceptor,过滤器Filter
目录 拦截器Interceptor 过滤器Filter 关于过滤器的前置知识可以参考: 过滤器在springboot项目的应用 一,使用WebfilterServletComponentScan 注解 1 创建过滤器类实现Filter接口 2 在启动类中添加 ServletComponentScan 注解 二,创建…...
【程序+论文】大规模新能源并网下的火电机组深度调峰经济调度
目录 1 主要内容 讲解重点 2 讲解视频及代码 1 主要内容 该视频为《大规模新能源并网下的火电机组深度调峰经济调度》代码讲解内容,该程序有完全对照的论文,以改进IEEE30节点作为研究对象,系统包括5个火电机组和2个新能源机组,…...
【win11 】win11 键盘测试
我的键盘是支持mac和win的,fn tab 就能切换,有可能是用错了模式,导致 我alt a 就会弹出 win11的 wifi 等菜单控制 键盘测试网站 https://keyboard.bmcx.com/ 识别到我按下的是alt...
再识动静态库
动静态库 1 手动制作静态库2 手动调用静态库方式一:(安装到系统)方式二:(和源文件一起)方式三:(使用带路径的库) 3 动态库制作与使用方式一:拷贝到系统方式二…...
前端 uni-app 初步使用指南
在数字化浪潮下,实现应用多端适配成为开发者的刚需。uni-app 凭借 “一次编写,多端运行” 的特性,极大提升了开发效率,成为前端开发的热门选择。如果你是首次接触 uni-app,这篇文章将带你开启 uni-app 的使用之旅&…...
尼卡音乐 1.1.1 | 免费畅听全网音乐,支持无损下载,无广告无需注册登录
尼卡音乐是一款可以免费畅听全网音乐的应用程序,支持免费下载无损高品质音源,并且没有任何广告,无需注册登录。用户可以轻松搜索全网无损音质音源,并可将其他音乐APP的歌单导入,让音乐陪你开心一整天。该应用彻底拒绝臃…...
33.降速提高EMC能力
降速提高EMC能力 1. 电磁兼容问题的错误累积效应2. 降速减少累积效应的机理分析 1. 电磁兼容问题的错误累积效应 2. 降速减少累积效应的机理分析 降速之后,信号的波形更完整,容错空间更大;另外边沿变缓,对外干扰也会减小。...
【赵渝强老师】TiDB的MVCC机制
TiDB是一款开源的国产分布式关系型数据库。TiKV是TiDB的行存引擎,它支持多版本并发控制(Multi-Version Concurrency Control,MVCC)。假设有这样一种场景:某客户端A在写一个Key,另一个客户端B同时在对这个Key进行读操作。如果没有数据的多版本…...
数电填空题整理(适用期末考试)
在下列门电路中,OC门能实现“线与”逻辑功能; 三态门能用于总线结构的数 据传输;传输门 能实现模拟信号的双向传输。 并联比较型A/D转换器的转换速度最快, 双积分型A/D转换器的稳定性和抗干扰能力最好 TTL与非门多余的输入端应该…...
node核心学习
目录 1-1node概述 1-2全局对象 1-3Node的模块化细节 1-4Node中的ES模块化 1-5基本内置模块 OS模块: path模块: url模块: util模块: 1-6文件IO I/O:input output fs模块的方法 代码示例: 练习…...
基于 PyQt 的YOLO目标检测可视化界面+ nuitka 打包
在人工智能和计算机视觉领域,YOLO(You Only Look Once)是一种广泛使用的实时目标检测算法。为了直观地展示YOLO算法的检测效果,我们使用Pyqt框架进行检测结果的可视化,同时为了使其能够脱离Python环境,我们…...
234树和红黑树
首先,把目光聚集在234树中 以下是234的三种节点(可以有更多这里使用以下的三个): 右侧是节点转换成红黑树节点的样子。 接下来会用以下序列进行1234树的搭建和红黑树的搭建: 首先是234树 2-3-4树(234树&…...