教育学论文降AI工具免费推荐:2026年教育学毕业论文AIGC超标4.8元亲测完整方案
2026/7/26 5:31:18
既然进程 A 和 进程 B 的内存是隔离的,那它们怎么交换数据?答案:找一个它们都能看到的“第三者”。
这个“第三者”通常是操作系统内核。
这是 Linux 中最常见的 IPC 形式,就是我们在命令行里用的竖线|。
管道在内核中本质上是一块内存缓冲区。 但 Linux 把它抽象成了文件。这意味着你可以用read和write系统调用来操作它,就像操作普通文件一样。
fork,子进程才能继承父进程打开的文件描述符。pipe()C
#include <unistd.h> int pipe(int pipefd[2]);pipefd[0]:读端(Reader)。pipefd[1]:写端(Writer)。创建管道本身并不难,难的是如何让父子进程各执一端。
第一步:父进程创建管道父进程调用pipe,此时父进程同时拥有读端和写端。
第二步:父进程 Fork 子进程fork之后,子进程拷贝了父进程的文件描述符表 (File Descriptor Table)。重点:虽然 PCB 拷贝了,但它们指向的struct file(文件结构体)是同一个。所以子进程也有fd[0]和fd[1],指向同一个内核缓冲区。
第三步:关闭不需要的端口(构建单向信道)管道设计为单向。
fd[0](读端),保留fd[1]。fd[1](写端),保留fd[0]。我们写一个简单的程序:父进程往管道里写字符串,子进程读取并打印。
#include <iostream> #include <unistd.h> #include <string.h> #include <sys/wait.h> #include <sys/types.h> using namespace std; int main() { // 1. 创建管道 int pipefd[2] = {0}; if (pipe(pipefd) < 0) { perror("pipe"); return 1; } // 2. 创建子进程 pid_t id = fork(); if (id < 0) { perror("fork"); return 2; } if (id == 0) { // --- 子进程 (Reader) --- // 3. 子进程关闭写端 close(pipefd[1]); char buffer[1024]; while (true) { // 4. 从管道读取 // 如果管道没数据,read 会自动阻塞等待!(类似 wait 的状态) ssize_t s = read(pipefd[0], buffer, sizeof(buffer) - 1); if (s > 0) { buffer[s] = 0; cout << "Child got message: " << buffer << endl; } else if (s == 0) { // 写端关闭了,读端就会读到 0 (EOF) cout << "Writer quit, Child quit." << endl; break; } else { perror("read"); break; } } close(pipefd[0]); exit(0); } // --- 父进程 (Writer) --- // 3. 父进程关闭读端 close(pipefd[0]); const char *msg = "Hello Child, I am Father."; int count = 0; while (count < 5) { char out_buffer[1024]; snprintf(out_buffer, sizeof(out_buffer), "%s [%d]", msg, count++); // 4. 写入管道 write(pipefd[1], out_buffer, strlen(out_buffer)); sleep(1); // 故意慢一点,看看子进程会不会等 } // 5. 任务结束,关闭写端 // 这一步非常重要!关闭写端后,子进程的 read 才会返回 0 (EOF) close(pipefd[1]); waitpid(id, nullptr, 0); cout << "Father wait success." << endl; return 0; }通过上面的代码,我们可以总结出管道的 4 种“脾气”,这体现了进程同步的思想。
read完剩余数据后,会返回0(表示 End Of File)。这是子进程知道“父进程写完了”的信号。SIGPIPE(13号信号),直接杀死写端进程。cat huge_file.txt | head -n 5,head读了 5 行就退出了(关闭读端),此时cat进程会被操作系统发信号干掉,避免它继续读取巨大的文件浪费资源。