C ++中的编码管道“|”:管道输入后为什么空行进入getline?

问题描述 投票:1回答:1

我正在编写一个模拟shell,我正在使用dup2编写管道编码。这是我的代码:

bool Pipe::execute() {
    int fds[2]; //will hold file descriptors
    pipe(fds);
    int status;
    int errorno;
    pid_t child;
    child = fork();

    if (-1 == child) {
        perror("fork failed");
    }
    if (child == 0) {
        dup2(fds[1], STDOUT_FILENO);
        close(fds[0]);
        close(fds[1]);
        this->component->lchild->execute();
        _exit(1);
    }
    else if (child > 0) {
        dup2(fds[0], STDIN_FILENO);
        close(fds[0]);
        close(fds[1]);
        this->component->rchild->execute();
        waitpid(child, &status, 0);
        if ( WIFEXITED(status) ) {
            //printf("child exited with = %d\n",WEXITSTATUS(status));
            if ( WEXITSTATUS(status) == 0) {
                cout << "pipe parent finishing" << endl;
                return true;
            }
        }
        return false;
    }
}

this->component->lchild->execute();this->component->rchild->execute();在相应的命令上运行execvp。我已经确认每个都通过在父进程中打印出一个语句来返回。然而,在我的Pipe::execute()中,似乎子进程没有完成,因为父进程中的cout语句从未打印,并且在初始化提示符($)后出现分段错误(参见图片)。这是在每次执行后初始化提示符的main函数:

int main()
{
    Prompt new_prompt;
    while(1) {
        new_prompt.initialize();
    }
    return 0;
}

这是initialize()功能:

void Prompt::initialize()
{
    cout << "$ ";
    std::getline(std::cin, input);

    parse(input);
    run();
    input.clear();
    tokens.clear();
    fflush(stdout);
    fflush(stdin);
    return;
}

似乎ls | sort运行正常,但是当初始化提示时,getline将读入空行。我尝试过使用cin.clear(),cin.ignore和上面的fflush和clear()行。该空白字符串被“解析”,然后调用run()函数,该函数尝试取消引用空指针。关于为什么/这个空白行被输入getline的任何想法?我该如何解决这个问题?谢谢!

更新:管道中的父进程现在正在完成。我也注意到我的I / O重定向类(><)也遇到了seg错误。我想我不是正在刷新流或正确关闭文件描述符...

这是我的孩子和孩子的qazxsw poi功能:

execute()
c++ pipe fork getline dup2
1个回答
2
投票

这是错误:

bool Command::execute() {
    int status;
    int errorno;
    pid_t child;
    vector<char *> argv;
    for (unsigned i=0; i < this->command.size(); ++i) {
        char * cstr = const_cast<char*>(this->command.at(i).c_str());
        argv.push_back(cstr);
    }
    argv.push_back(NULL);
    child = fork();
    if (-1 == child) {
        perror("fork failed");
    }
    if (child == 0) {
        errorno = execvp(*argv.data(), argv.data());
        _exit(1);

    } else if (child > 0) {
        waitpid(child, &status, 0);
        if ( WIFEXITED(status) ) {
            //printf("child exited with = %d\n",WEXITSTATUS(status));
            if ( WEXITSTATUS(status) == 0) {
                //cout << "command parent finishing" << endl;
                return true;
            }
        }
        return false;
    }
}

你正在为父母关闭stdin,而不仅仅是正确的孩子。在此之后,父进程的stdin与正确子进程的stdin相同。

之后

else if (child > 0) {
    dup2(fds[0], STDIN_FILENO);
    close(fds[0]);
    close(fds[1]);
    this->component->rchild->execute();

试图读取左子的输出,而不是原始的stdin。到那时,左边的孩子已经完成,管道的一端已经关闭。这使得读取stdin失败,并使std::getline(std::cin, input); 保持原始状态不变。

编辑:您的设计有一个小问题和一个主要缺陷。小缺陷是你不需要在input的叉子。主要缺陷是孩子应该是重定向流并关闭描述符的人。

只需通过fork()传递输入和输出参数,然后让孩子们使用dup2。不要忘记使它也关闭不相关的管端。如果不这样做,左边的孩子将完成,但其输出管道将继续生活在其他过程中。只要该描述符的其他副本存在,那么正确的孩子在阅读其管道末端时永远不会获得EOF - 并且永远不会有周块。

© www.soinside.com 2019 - 2024. All rights reserved.