进程间通信(IPC)
进程间通信(IPC)是操作系统中非常重要且基础的概念,涉及到不同进程之间如何交换数据和同步操作。下面我会一个一个地详细讲解这几种常见的IPC方式:管道(包含匿名管道和有名管道)、消息队列、共享内存、信号量、Socket通信,内容尽量用通俗易懂的语言,并结合具体原理、优缺点、使用场景及简要示例说明。
一、进程间通信(IPC)是什么?
**进程间通信(IPC,Inter-Process Communication)**指的是让运行在操作系统上的不同进程之间能够交换数据、通知对方、协调动作的技术或机制。
操作系统中的进程通常是相互独立、拥有自己私有的地址空间的,不同进程间不能直接访问对方的内存空间。所以需要通过操作系统提供的IPC机制,让进程们“聊聊天”、“传数据”,做到协同工作。
IPC的应用非常广泛,比如:
- web服务器的多进程之间交换请求信息
- 生产者消费者模型进程协调共享资源
- client-server模式下客户端和服务端进程交互
二、管道(Pipe)
1. 管道基本概念
管道(Pipe) 是最早的进程间通信机制之一。它是一种半双工通信方式(数据只能单方向流动),提供了一个缓冲区,实现一个进程写入,另一个进程读取。
管道本质上是内核中的一个缓冲区,两个进程通过读写这个缓冲区交换数据。
2. 匿名管道(Anonymous Pipe)
-
特点:
- 只能用于有亲缘关系的进程之间,通常父子进程
- 管道的两端表现为文件描述符:一个写端,一个读端
- 是半双工的(单向通信)
-
使用场景:
- 父子/兄弟进程简单数据传递,比如shell中的命令管道
ls | grep "txt"
- 父子/兄弟进程简单数据传递,比如shell中的命令管道
-
创建方式:
- 在Unix/Linux系统,调用
pipe(int pipefd[2])
创建匿名管道 - 返回两个文件描述符:
pipefd[0]
用于读,pipefd[1]
用于写
- 在Unix/Linux系统,调用
-
示例:
int pipefd[2]; pipe(pipefd); // 创建管道pid_t pid = fork(); if (pid == 0) {// 子进程:关闭读端,写数据close(pipefd[0]);write(pipefd[1], "Hello Parent", 12);close(pipefd[1]); } else {// 父进程:关闭写端,读数据close(pipefd[1]);char buf[100];int n = read(pipefd[0], buf, sizeof(buf));buf[n] = '\0';printf("Received from child: %s\n", buf);close(pipefd[0]); }
3. 有名管道(FIFO,Named Pipe)
-
特点:
- 管道有名字存在文件系统中,路径类似
/tmp/myfifo
- 可以实现任意两个进程间通信,无需亲缘关系
- 依旧是单向的(同一管道路径读写不可逆,为双向则需要两个FIFO)
- 管道有名字存在文件系统中,路径类似
-
创建方式:
- 使用
mkfifo()
系统调用创建 - 使用时如普通文件打开读写即可
- 使用
-
示例:
- 创建有