IPC(进程间通信)概述
进程空间独立,但进程间常需数据共享或交换,因此需要IPC机制。IPC允许不同进程高效协作,例如数据传输、同步操作等。IPC方式多样,可根据需求选择。
IPC主要种类
- 古老通信方式:包括无名管道、有名管道和信号。
- IPC对象通信:如共享内存、信号量集(消息队列相对少用)。
- Socket通信:适用于网络环境。
管道底层实现基于队列,支持高效数据传输。下面重点讨论无名管道和有名管道。
无名管道(匿名管道)
无名管道仅适用于有亲缘关系的进程(如父子进程)。它基于文件描述符操作,特性如下:
- 半双工模式:通常用作单工(单向通信)。
- 不支持定位操作(如
lseek)。 - 使用文件IO(
open,read,write,close)或标准IO(带缓冲区)。 - 阻塞行为:
- 读端存在时,写操作超过64KB会阻塞。
- 写端存在时,读操作在管道为空时会阻塞。
- 读端关闭后,写操作会导致写进程退出。
- 写端关闭后,读操作返回0表示结束。
编程步骤
- 创建管道。
- 读写管道。
- 关闭管道。
函数原型
c
int pipe(int pipefd[2]);
- 功能:创建并打开无名管道。
- 参数 :
pipefd[0]:固定读端。pipefd[1]:固定写端。
- 返回值:成功返回0,失败返回-1。
示例使用:
c
#include <unistd.h>
#include <stdio.h>
int main() {
int pipefd[2];
pid_t pid;
if (pipe(pipefd) == -1) {
perror("pipe error");
return -1;
}
pid = fork();
if (pid == 0) { // 子进程:写数据
close(pipefd[0]); // 关闭读端
write(pipefd[1], "Hello", 6);
close(pipefd[1]);
} else if (pid > 0) { // 父进程:读数据
close(pipefd[1]); // 关闭写端
char buf[10];
read(pipefd[0], buf, sizeof(buf));
printf("Received: %s\n", buf);
close(pipefd[0]);
}
return 0;
}
有名管道
有名管道(FIFO)适用于任意单机进程,在文件系统中可见(有路径名)。特性与无名管道一致,额外特性:
- 一端未打开时,
open函数会阻塞。
编程步骤
- 创建有名管道。
- 打开有名管道。
- 读写管道。
- 关闭管道。
- 卸载有名管道(可选)。
函数原型
c
int mkfifo(const char *pathname, mode_t mode);
- 功能:创建有名管道文件。
- 参数 :
pathname:文件路径和名称。mode:八进制权限(如0666)。
- 返回值:成功返回0,失败返回-1。
示例使用:
c
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
int main() {
const char *fifo_path = "/tmp/myfifo";
// 创建有名管道
if (mkfifo(fifo_path, 0666) == -1) {
perror("mkfifo error");
return -1;
}
// 进程A:写数据
int fd = open(fifo_path, O_WRONLY);
write(fd, "Data from A", 12);
close(fd);
// 进程B:读数据
fd = open(fifo_path, O_RDONLY);
char buf[20];
read(fd, buf, sizeof(buf));
close(fd);
// 可选:卸载管道
unlink(fifo_path);
return 0;
}
总结
- 无名管道适合亲缘进程,简单高效。
- 有名管道扩展至任意进程,但需文件系统管理。
- 管道通信需注意阻塞和关闭行为,避免死锁或数据丢失。实际应用中,结合进程同步机制(如信号量)可增强可靠性。