Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 管道分叉过程中的程序崩溃_C_Fork_Execv_Broken Pipe_Write Error - Fatal编程技术网

C 管道分叉过程中的程序崩溃

C 管道分叉过程中的程序崩溃,c,fork,execv,broken-pipe,write-error,C,Fork,Execv,Broken Pipe,Write Error,我正在为课程作业编写一个基本的shell,它将在给定的路径列表中找到一个命令,并执行该命令。它还用于处理管道。 然而,当我分叉一个子进程时,我在gdb中得到一条“Write error:break Pipe”消息,程序突然终止 我似乎无法理解为什么会发生这种情况,因为我一直在谨慎地打开和关闭正确的管道,并且过程分叉似乎按照预期工作。有C和unix编程经验的人能帮我诊断这个问题吗?我的fork实现/管道实现是否存在逻辑错误 //commands is of the format {"ls -al"

我正在为课程作业编写一个基本的shell,它将在给定的路径列表中找到一个命令,并执行该命令。它还用于处理管道。 然而,当我分叉一个子进程时,我在gdb中得到一条“Write error:break Pipe”消息,程序突然终止

我似乎无法理解为什么会发生这种情况,因为我一直在谨慎地打开和关闭正确的管道,并且过程分叉似乎按照预期工作。有C和unix编程经验的人能帮我诊断这个问题吗?我的fork实现/管道实现是否存在逻辑错误

//commands is of the format {"ls -al", "more", NULL}
//it represents commands connected by pipes, ex. ls -al | more
char **commands = parseArgv(consoleinput, SPECIAL_CHARS[4]);

int numcommands = 0;

while( commands[numcommands]!=NULL )
{
    numcommands++;
}

const int  numpipes = 2*(numcommands-1);

int pipefds[numpipes];

int i=0;
for(i=0; i<numpipes;i=i+2)
{
    pipe(pipefds+i);
}

int pipe_w = 1;
int pipe_r = pipe_w - 3;
int curcommand = 0;

while(curcommand < numcommands)
{
    if(pipe_w < numpipes)
    {
        //open write end
        dup2(pipefds[pipe_w], 1);
    }

    if(pipe_r > 0)
    {
        //open read end
        dup2(pipefds[pipe_r], 0);
    }

    for(i=0;i<numpipes;i++) //close off all pipes
    {
        close(pipefds[i]);
    }

    //Parse current command and Arguments into format needed by execv

    char **argv = parseArgv(commands[curcommand], SPECIAL_CHARS[0]);

    //findpath() replaces argv[0], i.e. command name by its full path ex. ls by /bin/ls
    if(findPath(argv) == 0)
    {
        int child_pid = fork();

        //Program crashes after this point
        //Reason: /bin/ls: write error, broken pipe

        if(child_pid < 0)
        {
            perror("fork error:");
        }
        else if(child_pid == 0)     //fork success
        {
            if(execv(argv[0], argv) == -1)
            {
                perror("Bad command or filename:");
            }

        }
        else
        {
            int child_status;
            child_pid = waitpid(child_pid, &child_status, 0);
            if(child_pid < 0)
            {
                perror("waitpid error:");
            }
        }
    }
    else
    {
        printf("Bad command or filename");
    }
    free(argv);

    curcommand++;
    pipe_w = pipe_w + 2;
    pipe_r = pipe_r + 2;
}

//int i=0;
for(i=0;i<numpipes;i++) //close off all pipes
{
    close(pipefds[i]);
}

free(commands);
//命令的格式为{“ls-al”、“more”、NULL}
//它表示通过管道连接的命令,例如ls-al | more
char**commands=parseArgv(控制台输入,特殊字符[4]);
int numcommands=0;
while(命令[numcommands]!=NULL)
{
numcommands++;
}
常量int numpipes=2*(numcommands-1);
内部管道[numpipes];
int i=0;
对于(i=0;i=0)
{
//开放读端
dup2(pipefds[pipe_r],0);
}

for(i=0;i在fork()调用之后,即在子进程中,复制文件描述符是正确的方法。
另外,waitpid()调用使一个子进程等待另一个子进程,shell挂起调用应在循环后移动到,即父级应等待所有子级。

您可以构造一个吗?在关闭正常的标准输入/输出描述符之前复制管道描述符,始终检查错误。您还应在子级中复制它们。无关:
if(pipe\r>0)
应为
if(pipe\r>=0)
IMHO。如果我读对了,您将在循环的第一个过程中关闭所有管道。这似乎没有什么效果。感谢大家的帮助。对于拼写错误,很抱歉,如果(管道>=0)…pipe_w-3,因为当前命令应从最后一个命令的读取端读取,该读取端相隔两个元素。错误检查提示(dup2(pipefds[pire_r])<0)对诊断损坏的管道有很大帮助。