嵌入式Linux:进程间通信机制
发布时间 - 2025-06-20 00:00:00 点击率:次由于每个进程都有自己独立的地址空间,不像线程共享同一地址空间,进程之间的通信需要特定的机制。
单个进程内部的模块(如函数)之间的通信相对简单,可以通过全局变量、参数传递等方式实现,但进程间通信相对复杂,因为不同进程彼此隔离,不共享内存。
虽然大多数普通应用程序是单进程、多线程的,不需要进程间通信的复杂性,但在一些复杂或大型应用中,尤其是服务器或图形用户界面(GUI)程序,可能会使用多进程架构来提升性能或简化设计。
这种情况下,IPC 机制就变得非常重要。
1、进程间通信机制
Linux 系统继承了 UNIX 系统的丰富 IPC 机制,并对其进行了扩展和改进。
UNIX 系统的进程间通信大致可以分为两大流派:
System V IPC(由 AT&T 贝尔实验室主导发展):改进了 UNIX 早期的进程间通信手段,形成了适用于单台计算机的 IPC 机制,主要包括信号量、消息队列和共享内存。BSD 套接字通信(由加州大学伯克利分校主导发展):BSD 在网络通信和分布式系统方面做出了重要贡献,跳出了进程间通信局限于单个计算机的限制,形成了基于套接字(Socket)的通信机制,广泛用于网络应用程序。Linux 将这两大体系都继承了下来,并在此基础上发展了 POSIX IPC。
POSIX(Portable Operating System Interface for Unix)标准化了多种 UNIX 系统功能,包括进程间通信,弥补了 System V IPC 的一些不足。
UNIX 传统的 IPC 机制包括管道、FIFO 和信号,这些机制最早由 UNIX 系统引入,适用于简单的单机进程间通信。
管道(Pipe):一种单向、半双工的通信机制,通常用于父子进程间的数据传递。父进程可以写入数据,子进程可以读取。FIFO(命名管道):类似于管道,但通过文件系统实现,任何进程都可以通过路径访问该管道,实现双向通信。信号(Signal):信号是一种用于进程间异步通知的机制,可以用于进程之间的简单通信或事件通知,例如 SIGINT(Ctrl+C 发送的中断信号)。1.2、System V IPCSystem V IPC 是 UNIX 的增强版本,主要包括信号量、消息队列和共享内存,适合需要更复杂的进程同步与数据共享的场景。
信号量(Semaphore):用于进程间的同步,通常用于控制对共享资源的访问。信号量用于防止多个进程同时访问同一资源,避免资源争用问题。消息队列(Message Queue):允许进程以消息的形式发送和接收数据。消息队列是一种先进先出(FIFO)的结构,支持不同类型的消息,使得进程可以基于消息类型进行处理。共享内存(Shared Memory):进程之间共享同一块内存区域,允许它们直接读写数据。这是最有效的 IPC 方式,因为数据不需要在进程之间复制。1.3、POSIX IPCPOSIX IPC 是 System V IPC 的改进版本,旨在解决 System V IPC 在灵活性和可移植性上的一些不足。
POSIX 标准为 UNIX 系统间的兼容性提供了统一的接口,使得程序可以更方便地在不同的 UNIX 系统间移植。
POSIX 信号量:与 System V 信号量类似,用于进程同步,但提供了更灵活的接口和更强的实时性支持。POSIX 消息队列:改进了 System V 消息队列,允许指定消息的优先级,并提供更简单的接口。POSIX 共享内存:与 System V 共享内存类似,但具有更好的兼容性和可移植性,接口设计更加现代化。1.4、套接字(Socket)通信套接字是一种既可以用于本地进程间通信,也可以用于网络通信的机制,支持双向数据传输。
基于套接字的 IPC 可以实现非常灵活的通信模式,例如客户端-服务器架构,适合在多台计算机之间传递数据。
各类 IPC 机制的对比和应用场景:
2、管道(Pipe)
管道是一种半双工(单向)的通信方式,通常用于父子进程之间的通信。一个进程可以向管道写入数据,另一个进程从管道读取数据。
Linux 提供了无名管道和命名管道两种类型。
无名管道(Anonymous Pipe):只能在具有亲缘关系的进程间使用,比如父进程和子进程。命名管道(Named Pipe 或 FIFO):通过文件系统中的路径来创建,任意进程都可以访问。示例:
代码语言:javascript代码运行次数:0运行复制int main() { int fd[2]; pipe(fd); // 创建无名管道 if (fork() == 0) { // 子进程 close(fd[0]); // 关闭读取端 write(fd[1], "Hello, parent!", 15); close(fd[1]); } else { // 父进程 char buffer[20]; close(fd[1]); // 关闭写入端 read(fd[0], buffer, sizeof(buffer)); printf("Received: %s\n", buffer); close(fd[0]); } return 0;}3、消息队列(Message Queue)
消息队列是一种先进先出的队列,允许进程以消息的形式发送和接收数据。
消息队列可以支持多种类型的消息,通过消息类型实现多种目的的通信。
示例:进程A可以向队列发送一个带有特定类型的消息,而进程B可以根据消息类型进行处理。
代码语言:javascript代码运行次数:0运行复制struct msgbuf { long mtype; char mtext[100];};int main() { key_t key = ftok("msgqueue", 65); int msgid = msgget(key, 0666 | IPC_CREAT); struct msgbuf message; message.mtype = 1; // 消息类型 snprintf(message.mtext, sizeof(message.mtext), "Hello Message Queue"); msgsnd(msgid, &message, sizeof(message.mtext), 0); return 0;}4、共享内存(Shared Memory)
共享内存是最快的 IPC 机制之一,因为进程之间直接访问同一块内存区域,而不需要拷贝数据。
通常使用 shmget()、shmat() 和 shmdt() 函数进行共享内存的创建和访问。
示例:
代码语言:javascript代码运行次数:0运行复制int main() { key_t key = ftok("shmfile",65); int shmid = shmget(key, 1024, 0666|IPC_CREAT); char *str = (char*) shmat(shmid, (void*)0, 0); strcpy(str, "Hello Shared Memory"); printf("Data written in memory: %s\n", str); shmdt(str); return 0;}5、信号量(Semaphore)
信号量是一种用于进程同步的机制,通常用于控制多个进程对共享资源的访问。
嵌入式系统中,信号量通常用来避免多个进程同时访问同一资源,防止数据竞争。
示例:信号量可以通过 semget() 和 semop() 函数来操作,用于锁定或解锁资源。
代码语言:javascript代码运行次数:0运行复制int main() { key_t key = ftok("semfile",65); int semid = semget(key, 1, 0666 | IPC_CREAT); struct sembuf sem_lock = {0, -1, 0}; // 减1操作 struct sembuf sem_unlock = {0, 1, 0}; // 加1操作 semop(semid, &sem_lock, 1); // 上锁 printf("Critical section\n"); semop(semid, &sem_unlock, 1); // 解锁 return 0;}6、套接字(Socket)
套接字不仅支持本地进程间通信,还可以用于网络通信。
基于套接字的 IPC 支持双向通信,比较灵活,适合嵌入式系统中进程之间需要频繁且复杂的数据交互的情况。
示例:
代码语言:javascript代码运行次数:0运行复制int main() { int sv[2]; socketpair(AF_UNIX, SOCK_STREAM, 0, sv); if (fork() == 0) { // 子进程 close(sv[0]); write(sv[1], "Hello from child", 16); close(sv[1]); } else { // 父进程 char buffer[20]; close(sv[1]); read(sv[0], buffer, sizeof(buffer)); printf("Received: %s\n", buffer); close(sv[
0]); } return 0;}7、信号(Signal)
信号是用来通知进程发生某种事件的机制。进程可以捕获、忽略或处理信号,典型的信号包括 SIGINT(中断信号)和 SIGKILL(杀死进程信号)。
示例:处理 SIGINT 信号(Ctrl+C)。
代码语言:javascript代码运行次数:0运行复制void sigint_handler(int sig) { printf("Caught signal %d\n", sig);}int main() { signal(SIGINT, sigint_handler); while (1) { printf("Running...\n"); sleep(1); } return 0;}进程间通信的机制多种多样,选择合适的方式取决于应用场景的需求。
# linux
# ai
# red
# JavaScript
# 架构
# 分布式
# for
# 全局变量
# 继承
# 接口
# signal
# Interface
# 线程
# 多线程
# 事件
# 异步
# 嵌入式系统
# unix
# 信号量
# 是一种
# 多个
# 可以通过
# 网络通信
# 适用于
# 形成了
# 两大
# 主要包括
# 应用程序
相关栏目:
【
网站优化151355 】
【
网络推广146373 】
【
网络技术251813 】
【
AI营销90571 】
相关推荐:
专业企业网站设计制作公司,如何理解商贸企业的统一配送和分销网络建设?
html5audio标签播放结束怎么触发事件_onended回调方法【教程】
Laravel的路由模型绑定怎么用_Laravel Route Model Binding简化控制器逻辑
进行网站优化必须要坚持的四大原则
想要更高端的建设网站,这些原则一定要坚持!
通义万相免费版怎么用_通义万相免费版使用方法详细指南【教程】
laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程
如何快速搭建高效简练网站?
Laravel如何安装使用Debugbar工具栏_Laravel性能调试与SQL监控插件【步骤】
Laravel Eloquent关联是什么_Laravel模型一对一与一对多关系精讲
Laravel怎么调用外部API_Laravel Http Client客户端使用
微信小程序 canvas开发实例及注意事项
详解MySQL数据库的安装与密码配置
Laravel Facade的原理是什么_深入理解Laravel门面及其工作机制
如何在服务器上三步完成建站并提升流量?
JavaScript中的标签模板是什么_它如何扩展字符串功能
如何在IIS中配置站点IP、端口及主机头?
Laravel如何使用Seeder填充数据_Laravel模型工厂Factory批量生成测试数据【方法】
Laravel如何升级到最新的版本_Laravel版本升级流程与兼容性处理
Laravel怎么自定义错误页面_Laravel修改404和500页面模板
Laravel怎么进行浏览器测试_Laravel Dusk自动化浏览器测试入门
Laravel如何创建自定义Facades?(详细步骤)
如何在云主机快速搭建网站站点?
Laravel如何监控和管理失败的队列任务_Laravel失败任务处理与监控
C#如何调用原生C++ COM对象详解
Laravel Blade组件怎么用_Laravel可复用视图组件的创建与使用
Python制作简易注册登录系统
Laravel如何处理JSON字段_Eloquent原生JSON字段类型操作教程
做企业网站制作流程,企业网站制作基本流程有哪些?
详解Android——蓝牙技术 带你实现终端间数据传输
手机钓鱼网站怎么制作视频,怎样拦截钓鱼网站。怎么办?
油猴 教程,油猴搜脚本为什么会网页无法显示?
成都网站制作公司哪家好,四川省职工服务网是做什么用?
制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?
原生JS获取元素集合的子元素宽度实例
软银砸40亿美元收购DigitalBridge 强化AI资料中心布局
在线制作视频的网站有哪些,电脑如何制作视频短片?
js实现获取鼠标当前的位置
高端智能建站公司优选:品牌定制与SEO优化一站式服务
如何彻底卸载建站之星软件?
如何用VPS主机快速搭建个人网站?
如何快速搭建二级域名独立网站?
香港服务器部署网站为何提示未备案?
如何在宝塔面板中修改默认建站目录?
如何自定义建站之星网站的导航菜单样式?
车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?
实例解析angularjs的filter过滤器
Laravel如何为API编写文档_Laravel API文档生成与维护方法
郑州企业网站制作公司,郑州招聘网站有哪些?
Laravel中的withCount方法怎么高效统计关联模型数量


0]); } return 0;}