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

C语言实现管道调用grep时子进程阻塞无法退出求助

问题分析与解决

你的grep子进程卡住无法退出的核心原因是父进程没有关闭管道的读写两端。当ls子进程执行完毕退出后,管道的写端仍被父进程保持打开状态,grep会一直等待管道中出现新数据,无法触发EOF(文件结束符),因此会持续阻塞无法正常退出。

具体修复步骤

  1. 父进程关闭管道两端:在fork完成所有子进程后,父进程必须主动关闭pfd[0]和pfd[1],让管道的写端完全关闭,grep读取到EOF后就会正常结束。
  2. 子进程关闭冗余描述符:虽然execvp会替换进程地址空间,但在dup2后关闭原管道描述符是更规范的做法,避免不必要的资源泄漏。

修复后的代码示例

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

int main()
{
    int i = 0;
    int pfd[2];
    if (pipe(pfd) != 0)
    {
        printf("Error creating pipe\n");
        exit(errno);
    }
    char **ptr = get_pipes(); // pipes as array of strings
    char *command = *ptr;

    while (command != NULL)
    {
        if (i == 2)
            break;                        // hard code to ignore all commands after 2nd pipe
        char **args = parse_cmd(command); // this parses a space-separated command as arguments
        pid_t pid = fork();

        if (pid == 0 && i == 0) // 1st pipe, 1st child
        {
            close(pfd[0]);   // 关闭管道读端
            dup2(pfd[1], 1); // 将标准输出重定向到管道写端
            close(pfd[1]);   // 关闭原管道写端,避免资源泄漏
            if (execvp(args[0], args) == -1)
            {
                fprintf(stderr, "%s: %s\n", args[0], strerror(errno));
                exit(EXIT_FAILURE);
            }
        }

        else if (pid == 0 && i == 1) // 2nd pipe, 2nd child
        {
            close(pfd[1]);   // 关闭管道写端
            dup2(pfd[0], 0); // 将标准输入重定向到管道读端
            close(pfd[0]);   // 关闭原管道读端,避免资源泄漏
            if (execvp(args[0], args) == -1)
            {
                fprintf(stderr, "'%s': %s\n", args[0], strerror(errno));
                exit(EXIT_FAILURE);
            }
        }
        else if (pid > 0) // parent
        {
            printf("Parent pid: %d and child's pid is %d\n", (int)getpid(), (int)pid);
        }

        command = *++ptr;
        i++;
    }

    // 父进程必须关闭管道两端,否则grep会一直阻塞等待
    close(pfd[0]);
    close(pfd[1]);

    pid_t zombie_pid;
    int status;

    do
    {
        zombie_pid = waitpid(-1, &status, 0);
        if (zombie_pid > 0) {
            printf("Child PID %d died with status %d\n", (int)zombie_pid, WEXITSTATUS(status));
        }
    } while (zombie_pid > 0);
}

额外说明

  • 管道的读写端必须被所有不再使用它的进程关闭,否则依赖EOF判断结束的进程(如grep、cat等)会持续阻塞。
  • 修复后的waitpid循环增加了判断,避免所有子进程退出后,zombie_pid为-1时输出错误信息。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.16 08:50:39