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

execvp重定向stdout问题:进程树中scanf无法读取父进程输出

进程二叉树管道通信问题修复

这段代码是用进程作为节点构建二叉树的一个片段,目标是通过中序遍历将数据传递给左子树。当前逻辑仅创建左子进程并再次执行./tpipe可执行文件,但执行./tpipe 0时,子进程中的scanf读取的是用户输入而非父进程printf输出的字符串。要求必须用dup2而非read/write等方法修复,因为每次启动程序时filedp都会重新初始化。

原精简代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
    if (argc < 2)
    {
        fprintf(stderr, "NEED MORE ARGUMENT\n");
        return 1;
    }
    int curDepth = atoi(argv[1]);
    int filedp[2];
    pipe(filedp);

    if (curDepth != 0)
    {
        char buf[100];
        scanf("%s", buf);
        fprintf(stderr, "buf is: %s\n", buf);
    }

    if (curDepth < 1)
    {
        int fd = fork();
        if (fd == 0)
        {
            close(filedp[0]);
            dup2(filedp[1], STDOUT_FILENO);
            dup2(filedp[0], STDIN_FILENO);
            printf("Example\n");
            char *k[] = {"./tpipe", "1", NULL};
            execvp("./tpipe", k);
        }
        else
        {
            wait(NULL); // parent
        }
    }
    else
    {
        fprintf(stderr, "IT IS LEAF!\n");
    }
    return 0;
}

问题分析

原代码的核心错误在于管道重定向逻辑混乱:

  • 子进程同时将STDOUT和STDIN绑定到管道的不同端,导致输出和输入的流向完全错误
  • 父进程没有将自身输出定向到管道,无法把数据传递给子进程

修复后的代码

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <assert.h>
#include <sys/wait.h>
int main(int argc, char *argv[])
{
    if (argc < 2)
    {
        fprintf(stderr, "NEED MORE ARGUMENT\n");
        return 1;
    }
    int curDepth = atoi(argv[1]);
    int filedp[2];
    pipe(filedp);

    if (curDepth != 0)
    {
        char buf[100];
        scanf("%s", buf);
        fprintf(stderr, "buf is: %s\n", buf);
    }

    if (curDepth < 1)
    {
        int fd = fork();
        if (fd == 0)
        {
            // 子进程只需读取管道数据,关闭写端并将STDIN重定向到管道读端
            close(filedp[1]);
            dup2(filedp[0], STDIN_FILENO);
            close(filedp[0]);

            char *k[] = {"./tpipe", "1", NULL};
            execvp("./tpipe", k);
            perror("execvp failed");
            exit(1);
        }
        else
        {
            // 父进程只需写入管道数据,关闭读端并将STDOUT重定向到管道写端
            close(filedp[0]);
            dup2(filedp[1], STDOUT_FILENO);
            close(filedp[1]);

            printf("Example\n");
            wait(NULL);
        }
    }
    else
    {
        fprintf(stderr, "IT IS LEAF!\n");
    }
    return 0;
}

修复说明

  1. 分工明确管道读写:父进程负责向管道写入数据,子进程负责从管道读取数据,避免双向绑定的逻辑混乱
  2. 正确重定向标准流:
    • 子进程将STDIN重定向到管道读端,这样scanf会自动读取管道中的父进程输出
    • 父进程将STDOUT重定向到管道写端,这样printf的内容会直接写入管道
  3. 关闭冗余文件描述符:重定向完成后关闭原管道描述符,避免资源泄漏,同时确保管道在进程退出时能正确触发EOF

内容的提问来源于stack exchange,提问作者Özgür Çavuşoğlu

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 07:20:09