首页/新闻资讯/正文详情

进程线程与 IPC 工控实践:多线程采集、共享内存、管道数据交互

发布时间:2026/9/25 2:36:16 来源:云帆数科 栏目:资讯中心
进程线程与 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的最佳组合。

相关推荐

YOLOv26在微小目标检测中的优化与应用:以果蝇计数为例
YOLOv26在微小目标检测中的优化与应用:以果蝇计数为例

1. 项目背景与核心价值果蝇计数在农业研究、食品安全和生物实验室中都是基础但极其耗时的任务。传统人工计数方法不仅效率低下(一个熟练技术员每小时最多处理20-30个样本),而且存在高达15%-20%的计数误差。我们团队开发的这套基于YOLOv26的自… · 2026/9/25 2:35:19

深入掌握Visual C++中COM/COM+技术:从核心原理到企业级应用实践
深入掌握Visual C++中COM/COM+技术:从核心原理到企业级应用实践

1. 项目概述:为什么今天还要啃COM/COM这块“硬骨头”?如果你是一位在Windows平台上用Visual C摸爬滚打多年的开发者,看到COM和COM这两个词,第一反应可能是“老古董”或者“历史包袱”。确实,在.NET、现代C乃至各种跨平… · 2026/9/25 2:35:13

VC++实战:灰度阈值变换算法实现与图像二值化处理
VC++实战:灰度阈值变换算法实现与图像二值化处理

1. 项目概述:从像素到决策的灰度阈值变换在数字图像处理的世界里,灰度阈值变换是一个看似简单,却蕴含着巨大能量的基础操作。它就像一位经验丰富的质检员,站在流水线旁,对每一个像素进行“非黑即白”的快速判断。无论是… · 2026/8/3 11:38:00

oh-my-opencode-slim 内置 MCP 服务器架构:context7 与 gh_grep 的配置、权限与禁用机制
oh-my-opencode-slim 内置 MCP 服务器架构:context7 与 gh_grep 的配置、权限与禁用机制

人工智能AI AgentAgent 编排AI 技能 【免费下载链接】oh-my-opencode-slim Lean, fine tuned Opencode multi agent suite Mix any models Auto delegate tasks 项目地址: https://gitcode.com/gh_mirrors/oh/oh-my-opencode-slim 点击查看 免费下载 本文围绕 oh… · 2026/9/25 2:36:14

英伟达暑期实习笔试样题解析:GPU体系结构与深度学习考点
英伟达暑期实习笔试样题解析:GPU体系结构与深度学习考点

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 2:36:14

使用 AWS SDK for .NET 构建 Amazon SES v2 优惠券新闻邮件工作流:从联系人列表到模板化群发
使用 AWS SDK for .NET 构建 Amazon SES v2 优惠券新闻邮件工作流:从联系人列表到模板化群发

示例工程教程后端 【免费下载链接】aws-doc-sdk-examples Welcome to the AWS Code Examples Repository. This repo contains code examples used in the AWS documentation, AWS SDK Developer Guides, and more. For more information, see the Readme.md file below. 项目地… · 2026/9/25 2:36:14

【AI】前沿速递 · 2026 年 7 月:用 TaoToken 统一 Key 打通开源大模型与智能体代码工作流
【AI】前沿速递 · 2026 年 7 月:用 TaoToken 统一 Key 打通开源大模型与智能体代码工作流

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 2:36:14

校园失物招领系统毕设资料包二次开发与答辩指南
校园失物招领系统毕设资料包二次开发与答辩指南

简介:这份资源是面向计算机相关专业在校学生与教师的校园失物招领系统毕业设计完整资料包,已获导师认可并通过答辩评审,适合作为毕设、课程设计、作业或项目初期立项演示的参考方案,也便于基础较好的学习者在此基础上二次开发扩展… · 2026/9/25 2:36:14

微信小程序汉字笔顺动画组件:Canvas渲染与避坑指南
微信小程序汉字笔顺动画组件:Canvas渲染与避坑指南

简介:这是一份面向微信小程序开发者的 Hanzi Writer 组件源码包,用于在小程序内快速集成汉字书写器,实现笔画顺序动画、写法演示与问答交互等教学功能。组件原仓库虽已停止维护,但作者提供了 npm 的 beta 安装方式,适合… · 2026/9/25 2:36:08

数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)
数值优化(Numerical Optimization)学习系列-03-共轭梯度方法(Conjugate Gradient)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战
创维E900V22D刷机全攻略:S905L3SB芯片兼容性解析与救砖实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:31

MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX
MQTT协议原理与Broker服务器搭建实战:从Mosquitto到EMQX

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/9/25 1:00:37

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码