简体   繁体   English

pipe 第二次卡住

[英]pipe second time stuck

I used pipe and dup2 to redirection the file descriptors but after the first command, the second execvp stuck, I used the for loop to circle multiple commands.I'm pretty sure the tokenize and buffer stuff works, If I run the first command, it works, but for the second command, it just stuck after the first command.我使用 pipe 和 dup2 来重定向文件描述符,但是在第一个命令之后,第二个 execvp 卡住了,我使用 for 循环来圈出多个命令。我很确定标记化和缓冲区的东西有效,如果我运行第一个命令,它可以工作,但是对于第二个命令,它只是在第一个命令之后卡住了。

#include <fstream>
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/wait.h>
#include <fcntl.h>

using namespace std;

char buffer[10][500];
char *args[50];
int fd[20];

void tokenFnc(int counter);

//int counter = 0;
int main(int argc, char *argv[])
{

    string input;
    cout << "myshell$";
    getline(cin, input);
    int k = 0;
    int counter = 0;
    int status_code;

    for (unsigned i = 0; i <= input.size(); i++)
    {
        if (i > 0 && input[i] == ' ' && input[i - 1] == '|')
        {
            continue;
        }
        if (input[i] == '|')
        {
            counter++;
            k = 0;
        }
        else
        {
            buffer[counter][k] = input[i];
            k++;
        }
    }

    //  int fd[(counter-1)*2];
    for (int i = 0; i < counter; i++)
    {
        pipe(fd + i * 2);
    }

    counter += 1; //how many commands

    for (int i = 0; i < counter; i++)
    {
        if (pipe(fd) == -1)
        {
            perror("pipe failed");
            return 1;
        }
        tokenFnc(i);

        int rc = fork();
        if (rc < 0)
        { // fork creation fail
            perror("fork failed\n");
            return 1;
        }
        if (rc == 0)
        { //child process
            if (i == 0 && counter > 1)
                dup2(fd[1], 1);

            if (i > 0 && i != counter - 1)
            {
                dup2(fd[(i - 1) * 2], 0);
                dup2(fd[(2 * i) + 1], 1);
            }
            if (i == counter - 1 && counter > 1)
                dup2(fd[(i - 1) * 2], 0);

            for (int k = 0; k < (counter - 1) * 2; k++)
            {
                close(fd[k]);
            }

            status_code = execvp(args[0], (char *const *)args);
            if (status_code == -1)
            { //error handling
                perror("Child process terminated fail");
                return 1;
            }
        }
    }
    int status;
    for (int i = 0; i < counter; i++)
    {
        pid_t pid = wait(&status);
        if (pid == -1)
        {
            perror("wait exective fail \n");
            return 1;
        }
        printf("process %i exits with %i\n", pid, status);
    }
    return 0;
}

void tokenFnc(int counter)
{
    int tokenCount = 0;
    char delim[] = " ";
    // cout << counter << endl;

    // cout << "The token are: " << endl;
    char *token = strtok(buffer[counter], delim);
    while (token)
    {
        //   cout << token << " ";
        token = strtok(NULL, delim);
        tokenCount++;
    }
    // cout << endl;

    int pos = 0;
    for (int i = 0; i < tokenCount; i++)
    {
        args[i] = (char *)&buffer[counter][pos];
        pos += strlen(args[i]) + 1;
        // cout << args[i] << ", ";
    }
    args[tokenCount] = (char *)nullptr;
    // cout << endl;
}
        for (int k = 0; k < (counter - 1) * 2; k++)
        {
            close(fd[k]);
        }

The shown code close s all the pre- pipe d file descriptors in each child process, here.显示的代码close每个子进程中的所有 pre- pipe d 文件描述符,here。

But it fails to do the same in the parent process, after starting all the child processes.但是在启动所有子进程后,它无法在父进程中执行相同的操作。 The opened file descriptors in the parent process prevent the child processes from properly detecting an end-of-file condition on the pipe that's connected to their standard input.父进程中打开的文件描述符会阻止子进程正确检测连接到其标准输入的 pipe 上的文件结束条件。 All the pipe descriptors are still open in the parent process.所有 pipe 描述符在父进程中仍处于打开状态。

Overall, the shown handling of pipe file descriptors seems to be overly complicated.总的来说,pipe 文件描述符的显示处理似乎过于复杂。 It should not be necessary to pre- pipe everything, but create one pipe at a time, when starting each child process.不需要预先pipe一切,而是在启动每个子进程时一次创建一个 pipe。 Connect the new process's standard input it to the file descriptor from the previous iteration's pipe (or standard input for the first child process);将新进程的标准输入连接到前一次迭代的 pipe 的文件描述符(或第一个子进程的标准输入); set up a pipe for the child process standard output (or to the parent process's standard output, for the last process in the pipeline);为子进程标准 output 设置 pipe(或父进程的标准 output,用于管道中的最后一个进程); and then just close a pair of file descriptors in the parent.然后只需关闭父级中的一对文件描述符。 Mission accomplished.任务完成。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM