0Pricing
C Academy · 课时

管道

父子进程通信

管道 是 CoddyKit 上的免费 C Academy 课时。 这是第 1 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C Academy 课程共包含 4 节课。

什么是管道

管道是相关进程之间的单向通信通道。一个进程将字节写入管道,另一个进程将其读出,就像数据传送带一样。

两个文件描述符

pipe() 调用会填充一个包含两个元素的数组:fd[0] 是读端,fd[1] 是写端。写入 fd[1] 的数据可以从 fd[0] 读取。

#include <unistd.h>
#include <stdio.h>

int make_pipe(int fd[2]) {
    if (pipe(fd) < 0) { perror("pipe"); return -1; }
    /* fd[0] read end, fd[1] write end */
    return 0;
}

与 fork 结合使用

执行 fork() 后,父进程和子进程共享管道的描述符。父进程与子进程正是通过这种方式通信的:一方写入,另一方读取。

关闭未使用的端

每个进程都应关闭自己不使用的一端。读取方关闭写端,写入方关闭读端。否则,读取方永远不会看到文件结束。

#include <unistd.h>

void parent_as_writer(int fd[2]) {
    close(fd[0]);              /* parent will not read */
    write(fd[1], "hello", 5);  /* parent writes */
    close(fd[1]);              /* signal EOF to reader */
}

父子进程示例

父进程写入一条消息,子进程读取它。双方各自关闭不需要的一端。

#include <unistd.h>
#include <stdio.h>

void demo(int fd[2]) {
    if (fork() == 0) {           /* child: reader */
        close(fd[1]);
        char buf[64];
        ssize_t n = read(fd[0], buf, sizeof buf - 1);
        buf[n] = 0;
        printf("child got: %s\n", buf);
        close(fd[0]);
    } else {                     /* parent: writer */
        close(fd[0]);
        write(fd[1], "hi child", 8);
        close(fd[1]);
    }
}

读取返回 EOF

当所有写端都关闭后,read 会返回 0,表示文件结束。如果仍有一个写端保持打开状态,读取方就会一直阻塞,等待更多数据;这是一个常见错误。

管道容量与阻塞

管道具有有限的缓冲区(通常为 64 KB)。缓冲区填满后,write 会阻塞,直到读取方取走数据。缓冲区为空时,read 会阻塞,直到数据到达。这种流量控制可以同步两个进程。

使用 dup2 重定向

dup2 可以将进程的标准输入或标准输出替换为管道的一端。Shell 正是通过这种方式实现 cmd1 | cmd2 的,将一个命令的输出连接到下一个命令的输入。

#include <unistd.h>

void stdout_to_pipe(int fd[2]) {
    close(fd[0]);
    dup2(fd[1], STDOUT_FILENO); /* writes to stdout go into pipe */
    close(fd[1]);
}

命名管道(FIFO)

普通管道只能连接相关进程。使用 mkfifo 创建的命名管道(FIFO)会出现在文件系统中,因此不相关的进程也可以通过路径打开它并进行通信。

#include <sys/stat.h>

int make_fifo(const char *path) {
    return mkfifo(path, 0666); /* creates a FIFO file */
}

SIGPIPE 风险

向读端已关闭的管道写入数据会触发 SIGPIPE,默认情况下会终止进程。您可以忽略此信号,或者检查 write 返回的 EPIPE 错误。

何时使用管道

管道非常适合父进程与子进程之间进行简单的单向流式通信,也适合将多个程序串联起来。对于双向通信或不相关进程之间的通信,请考虑使用 FIFO、套接字或共享内存。

快速检查

测试您对管道的理解。

回顾

您学会了使用管道进行父子进程通信。

  • pipe() 提供 fd[0](读端)和 fd[1](写端)
  • 与 fork 结合使用;关闭未使用的端
  • 所有写端关闭后,read 在 EOF 处返回 0
  • FIFO 可以连接不相关的进程;请注意 SIGPIPE

常见问题解答

「管道」课时是免费的吗?

是的 — 「管道」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C Academy 课程的其余内容,请升级到 CoddyKit PRO。 C Academy 课程共包含 4 节课。

「管道」这节课中我会学到什么?

父子进程通信 你通过在浏览器中直接运行的动手代码来练习 C Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 1 节课,共 4 节。

「管道」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C Academy 课中编写并运行代码吗?

能。每节 C Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. 管道
  2. 共享内存
  3. 消息队列
  4. 信号
← 返回 C Academy