You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用cat做管道缓冲的C程序写入后挂起,如何检查cat进程状态?

解决向管道写入后挂起并检查cat进程是否完成的问题

我来帮你搞定这个问题!你遇到的挂起其实是管道的典型死锁场景,咱们一步步拆解解决:

核心问题分析

你的程序挂起的根源是管道读写端没有正确关闭:当你创建管道并fork出cat进程后,主进程仍然持有管道的写端,cat进程会一直监听管道输入,直到所有写端都被关闭才会结束;而主进程如果在等待cat退出,就会形成互相等待的死锁。

修正后的示例代码

下面是修复后的完整代码,我会在后面标注关键改动点:

#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <sys/wait.h>
#include <string.h>
#include <unistd.h>

#define PIPE_READ 0
#define PIPE_WRITE 1

int main(int argc, char** argv) {
    int pipe_fd[2];
    pid_t cat_pid;

    // 创建管道
    if (pipe(pipe_fd) == -1) {
        perror("pipe failed");
        exit(EXIT_FAILURE);
    }

    // fork出cat进程
    cat_pid = fork();
    if (cat_pid == -1) {
        perror("fork failed");
        exit(EXIT_FAILURE);
    }

    if (cat_pid == 0) {
        // 子进程:执行cat,从管道读数据
        close(pipe_fd[PIPE_WRITE]); // 关闭子进程不需要的写端
        dup2(pipe_fd[PIPE_READ], STDIN_FILENO); // 把管道读端重定向到标准输入
        close(pipe_fd[PIPE_READ]); // 重定向后关闭原文件描述符

        execlp("cat", "cat", NULL); // 执行cat命令
        perror("execlp failed"); // 如果execlp返回,说明出错
        exit(EXIT_FAILURE);
    } else {
        // 父进程:向管道写数据
        close(pipe_fd[PIPE_READ]); // 关闭父进程不需要的读端

        // 写入测试数据
        const char* data = "Hello from parent process!\nAnother line.\n";
        if (write(pipe_fd[PIPE_WRITE], data, strlen(data)) == -1) {
            perror("write failed");
            exit(EXIT_FAILURE);
        }

        close(pipe_fd[PIPE_WRITE]); // 关键:写完后立即关闭写端,让cat知道没有更多输入

        // 检查cat进程是否完成
        int status;
        pid_t wait_result = waitpid(cat_pid, &status, 0);
        if (wait_result == -1) {
            perror("waitpid failed");
            exit(EXIT_FAILURE);
        }

        // 判断进程退出状态
        if (WIFEXITED(status)) {
            printf("cat进程正常退出,退出码:%d\n", WEXITSTATUS(status));
        } else if (WIFSIGNALED(status)) {
            printf("cat进程被信号终止,信号编号:%d\n", WTERMSIG(status));
        }
    }

    return EXIT_SUCCESS;
}

关键操作说明

  • 关闭无关管道端:不管父进程还是子进程,都要关闭自己不需要的管道端。子进程只需要读,所以关闭写端;父进程只需要写,所以关闭读端——这是管道使用的基本规范,避免进程误以为还有数据会进来。
  • 写完后立即关闭写端:这是解决挂起的核心!当父进程写完数据后,必须关闭管道的写端,这样cat进程读到管道的EOF后就会自动退出,不会一直阻塞等待输入。
  • 用waitpid检查进程状态:通过waitpid(cat_pid, &status, 0)可以阻塞等待cat进程结束,并获取它的退出状态:
    • WIFEXITED(status):判断进程是否正常退出
    • WEXITSTATUS(status):获取正常退出的退出码
    • WIFSIGNALED(status):判断进程是否被信号杀死
    • WTERMSIG(status):获取终止进程的信号编号

非阻塞检查进程状态的方案

如果你不想让主进程阻塞等待cat,可以用非阻塞模式定期检查:

// 非阻塞检查示例
bool cat_finished = false;
while (!cat_finished) {
    int status;
    pid_t result = waitpid(cat_pid, &status, WNOHANG);
    if (result == cat_pid) {
        // cat进程已结束
        cat_finished = true;
        if (WIFEXITED(status)) {
            printf("cat正常退出,退出码:%d\n", WEXITSTATUS(status));
        } else {
            printf("cat被信号终止,信号:%d\n", WTERMSIG(status));
        }
    } else if (result == 0) {
        // cat还在运行,父进程可以做其他操作
        printf("cat进程仍在运行...\n");
        sleep(1);
    } else {
        // 出错
        perror("waitpid failed");
        break;
    }
}

内容的提问来源于stack exchange,提问作者Simon Baars

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 04:04:44