Linux:进程间通信

[复制链接]
发表于 2026-10-3 22:32:44 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×

Linux 是多任务系统,一个程序运行时往往需要和别的程序交换数据。进程之间怎么把话说清楚,这就是进程间通信要解决的问题。本文按从简单到复杂的顺序,把管道、共享内存、消息队列、信号量这几类常用方式一次讲透,并给出各自适用场景和命令示例。

一、为什么需要进程间通信

单个进程的能力有边界:一个进程崩了,整个任务就断;想用多核 CPU,就得同时跑几个进程。多个进程一起干活时,它们之间必须能传递数据、同步节奏、协同状态,这就是进程间通信(IPC,Inter-Process Communication)存在的理由。

常见需求有三类:一是传数据(比如把统计结果交给另一个进程写库);二是同步(比如等一个进程算完再往下走);三是通知(比如子进程退出了,父进程要知道)。不同需求对应不同的通信机制,选错机制代码会写得又绕又慢。

二、管道:最朴素的通信方式

管道的本质是内核里的一段缓冲区,一个进程往里写,另一个进程从里读。它分两种。

1. 匿名管道

匿名管道没有名字,只能在有亲缘关系的进程之间用,通常通过 fork 继承文件描述符传递。最常见的用法是 shell 里的竖线:

ps -ef | grep nginx | grep -v grep

这条命令里,ps 的 stdout 接到了管道写端,grep nginx 从读端拿数据。匿名管道是半双工的,数据只能单向流,如果反过来用需要再建一条。

可以用 mkfifo 观察它的存在:

mkfifo /tmp/myfifo
ls -l /tmp/myfifo

2. 命名管道

命名管道在文件系统里有一个真实路径,不相关的两个进程也能通过它通信。创建后,进程 A 往路径写,进程 B 从这个路径读,互不认识也能对上话。

三、System V 共享内存:最直接的传数据方式

管道要先把数据写进内核缓冲区,再让对方读出来,中间多了一次拷贝。如果数据量很大而且要频繁交换,用共享内存更划算:两块进程地址空间映射到同一段物理内存,一方写完另一方立刻能看到,没有内核中转。

Linux 里的共享内存相关命令可以直接查看系统状态:

ipcs -m      # 查看共享内存段
ipcs -q      # 查看消息队列
ipcs -s      # 查看信号量

典型流程是:申请一个共享内存段(shmget),把它挂接到本进程地址空间(shmat),读写完之后脱离(shmdt)并删除(shmctl)。用完记得删,否则系统里会留下越积越多的僵尸内存段。

四、消息队列:带边界的管道

共享内存本身不负责同步,谁先写完谁先读到就靠运气。消息队列在此基础上加了一层:发送的数据按消息为单位收发,每条消息有类型,接收方可以按类型挑着收。它仍然是内核维护的缓冲区,适合中等数据量、需要按类型过滤的场景。

五、信号量:管住并发访问次数

信号量不传数据,只管计数。它常和共享内存搭配:用共享内存放数据,用信号量控制同一时刻最多有几个进程能进临界区。把计数初始化成 1,就退化成互斥量,保证同一时间只有一个进程写。

六、怎么选:一张对照表

  • 只有父子进程、数据量小、单向流:用匿名管道,代码量最少。
  • 无亲缘关系、想按路径通信:用命名管道。
  • 大数据量、需要反复读写、自己能做好同步:用共享内存 + 信号量。
  • 中等数据量、需要消息边界和类型过滤:用消息队列。
  • 只需要控制并发度、不传业务数据:用信号量单独用即可。

还有一个常备思路:如果只是想让另一个进程帮你做点事,rpc、socket、信号(kill 传信号)往往比原生 IPC 更好写,跨机器还能直接复用同一套代码。

七、几个容易踩的坑

  • 管道写端全部关闭后,读端再读会返回 EOF,不是阻塞等待,循环里要注意退出条件。
  • 写管道时如果读取方已经退出,写会收到 SIGPIPE 信号,程序直接被杀,需要提前忽略信号。
  • 共享内存段忘了删除,重启程序后看到旧数据,其实残留的还是上一段内存。
  • 信号量初始化为 0,接收方先跑就会死等,一般由服务端先创建并初始化。

小结

管道解决的是「能不能传」,共享内存解决的是「传得快不快」,消息队列解决的是「能不能按类型分」,信号量解决的是「谁先进去」。把这四层需求对上号,现场选机制基本不会错。

qidao123.com企服评测-应用市场 编辑提示

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表