进程线程与 IPC 工控实践:多线程采集、共享内存、管道数据交互
进程线程与 IPC 工控实践多线程采集、共享内存、管道数据交互一个进程干活太慢多线程协作像流水线数据怎么在进程间流转IPC就是工厂里的传送带。一、进程与线程从独门独户到合租室友进程是操作系统分配资源的基本单位每个进程有自己的内存空间、文件描述符——就像独门独户的住户互不打扰。线程是进程内的执行单元多个线程共享同一个进程的地址空间——就像合租室友共享客厅厨房但各有各的卧室栈空间。对比进程线程地址空间独立隔离共享同进程内创建开销大fork复制小轻量创建通信方式需IPC机制直接读写共享变量崩溃影响不影响其他进程可能拖垮整个进程调度OS内核调度OS内核调度(pthread)工控场景怎么选多线程采集多个传感器、并行处理数据——共享地址空间方便数据交换多进程核心采集和Web服务分离——隔离性强一个崩了另一个不受影响实际项目往往是混合架构主进程多线程采集子进程做网络/显示服务二、多线程采集架构设计一个典型的工控多线程采集架构┌─────────────────────────────────────────────┐ │ 主线程 │ │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │ │ │串口1│ │串口2│ │ CAN │ │ ADC │ ← 采集线程池 │ │ └─────┘ └─────┘ └─────┘ └─────┘ │ │ ↓ ↓ ↓ ↓ │ │ ┌──────────────────────────────┐ │ │ │ 数据缓冲区环形队列 │ ← mutex保护│ │ └──────────────────────────────┘ │ │ ↓ │ │ ┌──────┐ ┌──────┐ │ │ │处理线程│ │上报线程│ ← 工作线程 │ │ └──────┘ └──────┘ │ └─────────────────────────────────────────────┘核心思路采集线程只管收数据往缓冲区塞处理线程从缓冲区取数据加工上报线程把结果发出去。各线程通过互斥锁和条件变量协调。三、pthread编程基础3.1 创建与等待线程#includepthread.hvoid*thread_func(void*arg){intid*(int*)arg;printf(线程%d 开始工作\n,id);/* ... 干活 ... */returnNULL;}intmain(void){pthread_ttid;intarg1;pthread_create(tid,NULL,thread_func,arg);pthread_join(tid,NULL);/* 等待线程结束 */return0;}pthread_create创建线程传入函数指针和参数。pthread_join阻塞等待线程结束类似进程的wait。3.2 互斥锁Mutex多个线程同时写同一个缓冲区不加锁就是灾难——数据会被搅成一锅粥。pthread_mutex_tmtxPTHREAD_MUTEX_INITIALIZER;/* 加锁访问共享资源 */pthread_mutex_lock(mtx);/* ... 操作共享缓冲区 ... */pthread_mutex_unlock(mtx);锁的原则持锁时间尽量短只保护必要的数据操作别在锁里做sleep或IO。3.3 条件变量Condition Variable互斥锁只能防止并发冲突但线程间怎么通知对方条件变量就是信号灯——一个线程等信号另一个线程发信号。pthread_mutex_tmtxPTHREAD_MUTEX_INITIALIZER;pthread_cond_tcondPTHREAD_COND_INITIALIZER;/* 消费者等数据 */pthread_mutex_lock(mtx);while(buf_count0){pthread_cond_wait(cond,mtx);/* 等待自动解锁被唤醒后重新加锁 */}/* 取数据 ... */pthread_mutex_unlock(mtx);/* 生产者放数据后通知 */pthread_mutex_lock(mtx);/* 放数据到缓冲区 ... */buf_count;pthread_cond_signal(cond);/* 通知一个等待者 */pthread_mutex_unlock(mtx);为什么pthread_cond_wait要用while而非if因为可能被虚假唤醒——没有真正信号也被唤醒了所以要再检查一遍条件。四、IPC机制总览进程间通信Inter-Process Communication是多进程协作的桥梁IPC方式特点工控适用场景管道(pipe/fifo)半双工、字节流简单命令传递命名管道(mkfifo)有文件名、无关进程可用进程间命令/状态传递共享内存(shm)最快、零拷贝高速数据交换视频帧等消息队列(msg)有格式、按类型读取结构化命令分发信号(signal)异步通知、信息量少事件通知紧急停止等Socket网络或本地、最通用跨机器或本地进程通信工控最常用的三件套共享内存高速数据、命名管道命令传递、信号紧急通知。五、共享内存实战共享内存是最快的IPC方式——两个进程直接读写同一块内存不需要内核中转真正零拷贝。#includesys/shm.h#includestring.h#defineSHM_KEY0x1234#defineSHM_SIZE4096/* 进程A写入共享内存 */intwriter(void){intshmidshmget(SHM_KEY,SHM_SIZE,IPC_CREAT|0666);if(shmid0){perror(shmget);return-1;}void*addrshmat(shmid,NULL,0);/* 写入传感器数据 */sensor_data_t*data(sensor_data_t*)addr;data-temperature25.3f;data-timestamptime(NULL);shmdt(addr);return0;}/* 进程B读取共享内存 */intreader(void){intshmidshmget(SHM_KEY,SHM_SIZE,0666);if(shmid0){perror(shmget);return-1;}void*addrshmat(shmid,NULL,SHM_RDONLY);/* 只读映射 */sensor_data_t*data(sensor_data_t*)addr;printf(温度: %.1f, 时间: %ld\n,data-temperature,data-timestamp);shmdt(addr);return0;}共享内存本身没有同步机制必须配合互斥锁或信号量/* 共享内存中嵌入锁 */typedefstruct{pthread_mutex_tmtx;/* 进程间互斥锁 */intdata_ready;floattemperature;floathumidity;time_ttimestamp;}shm_buffer_t;/* 注意进程间mutex需要设置为PROCESS_SHARED属性 */pthread_mutexattr_tattr;pthread_mutexattr_init(attr);pthread_mutexattr_setpshared(attr,PTHREAD_PROCESS_SHARED);pthread_mutex_init(shm_buf-mtx,attr);六、管道实战命名管道命令传递命名管道FIFO在文件系统中有路径名任何进程都能打开它读写。适合进程间的命令传递——一个进程发命令另一个接收执行。#includesys/stat.h#includefcntl.h#defineFIFO_PATH/tmp/ic_cmd_fifo/* 创建命名管道 */mkfifo(FIFO_PATH,0666);/* 命令发送进程 */intsend_cmd(constchar*cmd){intfdopen(FIFO_PATH,O_WRONLY);write(fd,cmd,strlen(cmd)1);close(fd);return0;}/* 命令接收进程 */intrecv_cmd(void){intfdopen(FIFO_PATH,O_RDONLY);charbuf[128];read(fd,buf,sizeof(buf));printf(收到命令: %s\n,buf);close(fd);return0;}管道的特性默认阻塞——写端打开时读端阻塞等数据读端打开时写端阻塞等读者。这天然实现了等命令再执行。七、信号实战自定义信号通知信号是进程间最轻量的通知方式适合紧急事件通知——比如紧急停止或数据更新了。#includesignal.h/* 注册信号处理函数 */voidsigusr1_handler(intsig){printf(收到SIGUSR1: 数据已更新!\n);/* 触发重新读取共享内存 */}voidsigusr2_handler(intsig){printf(收到SIGUSR2: 紧急停止!\n);/* 立即停止采集关闭设备 */}intmain(void){signal(SIGUSR1,sigusr1_handler);signal(SIGUSR2,sigusr2_handler);while(1){pause();/* 等待信号 */}}/* 另一个进程发送信号 *//* kill -SIGUSR1 pid 通知数据更新 *//* kill -SIGUSR2 pid 紧急停止 */编程发送信号kill(target_pid,SIGUSR1);/* 通知目标进程 */信号局限携带信息量极少只有信号编号不能传数据。适合做触发器数据本身走共享内存或管道。八、完整代码示例多线程串口采集共享内存转发这是一个完整的工控采集架构多线程从多个串口采集数据通过共享内存转发给另一个进程处理。#includepthread.h#includesys/shm.h#includestdio.h#includestdlib.h#includestring.h#includeunistd.h#includetime.h#defineSHM_KEY0x5678#defineMAX_PORTS3#defineBUF_SIZE64typedefstruct{pthread_mutex_tmtx;pthread_cond_tcond;intcount;struct{intport_id;floatvalue;time_tts;}items[BUF_SIZE];}shm_ring_t;shm_ring_t*shm_buf;/* 采集线程 */void*collect_thread(void*arg){intport_id*(int*)arg;while(1){floatvalread_serial_port(port_id);/* 串口读取 */time_tnowtime(NULL);pthread_mutex_lock(shm_buf-mtx);if(shm_buf-countBUF_SIZE){shm_buf-items[shm_buf-count].port_idport_id;shm_buf-items[shm_buf-count].valueval;shm_buf-items[shm_buf-count].tsnow;shm_buf-count;pthread_cond_signal(shm_buf-cond);}pthread_mutex_unlock(shm_buf-mtx);usleep(100000);/* 100ms采集间隔 */}returnNULL;}/* 数据处理线程 */void*process_thread(void*arg){while(1){pthread_mutex_lock(shm_buf-mtx);while(shm_buf-count0){pthread_cond_wait(shm_buf-cond,shm_buf-mtx);}/* 处理所有数据 */for(inti0;ishm_buf-count;i){printf(端口%d: %.2f %ld\n,shm_buf-items[i].port_id,shm_buf-items[i].value,shm_buf-items[i].ts);}shm_buf-count0;pthread_mutex_unlock(shm_buf-mtx);}returnNULL;}intmain(void){/* 创建共享内存 */intshmidshmget(SHM_KEY,sizeof(shm_ring_t),IPC_CREAT|0666);shm_bufshmat(shmid,NULL,0);memset(shm_buf,0,sizeof(shm_ring_t));/* 初始化进程间互斥锁 */pthread_mutexattr_tmattr;pthread_mutexattr_init(mattr);pthread_mutexattr_setpshared(mattr,PTHREAD_PROCESS_SHARED);pthread_mutex_init(shm_buf-mtx,mattr);pthread_condattr_tcattr;pthread_condattr_init(cattr);pthread_condattr_setpshared(cattr,PTHREAD_PROCESS_SHARED);pthread_cond_init(shm_buf-cond,cattr);/* 启动采集线程 */pthread_ttids[MAX_PORTS];intport_ids[MAX_PORTS]{0,1,2};for(inti0;iMAX_PORTS;i){pthread_create(tids[i],NULL,collect_thread,port_ids[i]);}/* 启动处理线程 */pthread_tproc_tid;pthread_create(proc_tid,NULL,process_thread,NULL);/* 主线程等待 */for(inti0;iMAX_PORTS;i){pthread_join(tids[i],NULL);}pthread_join(proc_tid,NULL);shmdt(shm_buf);shmctl(shmid,IPC_RMID,NULL);return0;}九、工控IPC方案选择对比表场景推荐IPC原因多线程内部数据交换全局变量mutex同地址空间最简单最快高速数据流视频帧/ADC波形共享内存零拷贝最高带宽命令/指令传递命名管道有序可靠自带阻塞同步紧急事件通知信号(SIGUSR)最快响应异步触发结构化消息分发消息队列按类型读取灵活筛选跨网络通信Socket通用性强可跨机器选择原则内部用线程共享外部用IPC隔离。数据量大用共享内存命令传递用管道紧急事件用信号——三者搭配就是工控IPC的最佳组合。

相关新闻

【Bug已解决】FSDP + torch.nn.Parameter (MoE layer) lora fine-tuning doesn‘t work 解决方案

【Bug已解决】FSDP + torch.nn.Parameter (MoE layer) lora fine-tuning doesn‘t work 解决方案

【Bug已解决】FSDP torch.nn.Parameter (MoE layer) lora fine-tuning doesnt work 解决方案 一、现象长什么样 在做一个 MoE(混合专家)模型微调时,很多人会把多个专家存成一个 nn.ParameterList 或一个大的 torch.nn.Parameter 张量&#x…

2026/7/25 4:47:17 阅读更多 →
线性代数实战:齐次方程组 Ax=0、基础解系与 Python 零空间求解详解

线性代数实战:齐次方程组 Ax=0、基础解系与 Python 零空间求解详解

前言 在大学的线性代数课堂上,我们第一次接触到齐次线性方程组 A x = 0 Ax=0 Ax=0 时,也许只是为了应付考试而去反复做行初等变换。但如果你从事算法、AI、机器人控制或数据分析,你会发现这短短的一个公式,其实是现代工程中**寻找系统“隐藏自由度”**的核心利器。 今天我…

2026/7/25 4:47:17 阅读更多 →
LLM技术实战:从原理到企业级应用指南

LLM技术实战:从原理到企业级应用指南

1. 项目概述:为什么现在学习LLM正当时?过去一年里,大型语言模型(LLM)已经从实验室走向大众视野。从智能客服到代码生成,从创意写作到数据分析,这些拥有千亿级参数的"数字大脑"正在重塑…

2026/7/25 4:47:17 阅读更多 →

最新新闻

2026年AI编程助手对比:Claude Code与GitHub Copilot全解析

2026年AI编程助手对比:Claude Code与GitHub Copilot全解析

在实际开发工作中,AI编程助手已经成为提升效率的重要工具。2026年,Claude Code和GitHub Copilot作为两大主流选择,各自在代码补全、终端集成和开发体验上展现出不同特点。本文基于实际测试,从安装配置、核心功能、使用场景到性能表…

2026/7/25 5:01:22 阅读更多 →
通过CC Switch本地代理实现Codex接入DeepSeek的完整方案

通过CC Switch本地代理实现Codex接入DeepSeek的完整方案

最近在尝试将 AI 编程助手 Codex 接入 DeepSeek 模型时,发现很多教程都绕不开复杂的 API 配置和网络代理问题,对于只想快速体验的开发者来说门槛不低。本文将分享一套无需登录、通过本地代理工具 CC Switch 实现 Codex 接入 DeepSeek 的完整方案,从工具原理到每一步的安装配…

2026/7/25 5:01:22 阅读更多 →
大模型推理优化:核心技术与实践指南

大模型推理优化:核心技术与实践指南

1. 为什么大模型推理优化成为技术焦点 去年ChatGPT引爆全球AI热潮后,各类大语言模型应用如雨后春笋般涌现。但当我们真正把百亿级参数的模型部署到生产环境时,才发现推理性能才是制约落地的真正瓶颈。我亲身经历过一个典型场景:某金融客服系统…

2026/7/25 5:01:22 阅读更多 →
UE5风格化环境制作:从Nanite到Lumen的技术实践

UE5风格化环境制作:从Nanite到Lumen的技术实践

这次我们来深入探讨虚幻引擎UE5风格化环境制作的技术要点。对于游戏开发者和数字艺术创作者来说,掌握风格化环境制作不仅能提升项目视觉表现力,还能显著优化性能表现。本文将从实际制作流程出发,重点分析UE5在风格化环境创作中的核心工具链和…

2026/7/25 5:01:22 阅读更多 →
Spring AI(5) :对话机器人-会话记忆

Spring AI(5) :对话机器人-会话记忆

本章代码已分享至Gitee:https://gitee.com/lengcz/ai-study.git 文章目录会话记忆配置cors 跨域如何实现会话记忆遇到的问题跨域问题会话记忆 大模型是不具备记忆功能的,要想让大模型记住之前聊天的内容,唯一的办法就是把之前聊天的内容与新的提示词一起…

2026/7/25 5:01:22 阅读更多 →
Claude与GPT-Image-2国内免费使用方案与AI工具组合实战

Claude与GPT-Image-2国内免费使用方案与AI工具组合实战

1. 先搞清楚这几个工具到底能解决什么问题 Claude、GPT-Image-2(简称Image2)这类工具最近讨论度很高,但很多人下载安装后才发现根本用不起来,或者不知道具体能做什么。我花了几天时间实测了这几个工具的国内可用方案,先说结论: Claude :核心优势是代码理解和生成能力…

2026/7/25 5:00:22 阅读更多 →

日新闻

突破文档下载限制:kill-doc让你看到的都能保存

突破文档下载限制:kill-doc让你看到的都能保存

突破文档下载限制:kill-doc让你看到的都能保存 【免费下载链接】kill-doc 看到经常有小伙伴们需要下载一些免费文档,但是相关网站浏览体验不好各种广告,各种登录验证,需要很多步骤才能下载文档,该脚本就是为了解决您的…

2026/7/25 0:00:35 阅读更多 →
C++ string类模拟实现:从深拷贝到内存管理的完整指南

C++ string类模拟实现:从深拷贝到内存管理的完整指南

1. 项目概述:为什么我们要“手撕”string类?在C的学习道路上,尤其是从C语言过渡到C的“初阶”阶段,string类绝对是一个绕不开的核心。标准库里的std::string用起来太方便了,、find、substr,几个操作符和函数…

2026/7/25 0:00:35 阅读更多 →
三角洲寻宝鼠工具:高效文件搜索与资源管理实战指南

三角洲寻宝鼠工具:高效文件搜索与资源管理实战指南

1. 先搞清楚“三角洲寻宝鼠”到底是什么工具从名称来看,“三角洲寻宝鼠”更像是一个资源查找或文件检索类工具,而不是游戏或娱乐软件。这类工具的核心价值在于帮助用户快速定位特定资源,比如文档、图片、压缩包或特定格式的文件。如果你经常需…

2026/7/25 0:00:35 阅读更多 →

周新闻

Go语言静态资源打包方案对比与实践指南

Go语言静态资源打包方案对比与实践指南

1. 项目背景与核心需求在Go语言开发中,我们经常需要处理静态资源文件的打包问题。无论是Web应用的模板文件、前端资源,还是配置文件、证书等,都需要随程序一起分发。传统做法是将这些文件与编译后的二进制文件放在同一目录下,但这…

2026/7/24 3:59:20 阅读更多 →
Go语言实现高性能LDAP认证服务的架构与实践

Go语言实现高性能LDAP认证服务的架构与实践

1. 项目背景与核心价值LDAP(轻量级目录访问协议)作为企业级身份认证的黄金标准,已经服务了超过80%的财富500强公司。我在金融科技领域实施统一认证体系时,发现传统Java方案存在启动慢、内存占用高等痛点。而Go语言凭借其协程并发模…

2026/7/24 1:23:39 阅读更多 →
【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

【AI面试官实战指南】:用ChatGPT模拟10类高频技术岗面试,3天提升应答精准度92%

更多请点击: https://intelliparadigm.com 第一章:AI面试官实战指南的核心价值与适用场景 AI面试官并非替代人类HR的“黑箱工具”,而是以可解释、可审计、可迭代的方式,赋能招聘全链路的关键基础设施。其核心价值在于将主观经验沉…

2026/7/24 18:52:18 阅读更多 →

月新闻