Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/61.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_Process_Pipe - Fatal编程技术网

C 管道和工艺

C 管道和工艺,c,process,pipe,C,Process,Pipe,前提: 编写一个程序,向用户查询两个输入字符串。每个输入字符串都应该是一个unix命令,并且允许有参数。例如,输入1可以是ls-l,输入2可以是more。然后程序将创建一个管道和两个子进程。第一个子进程将运行第一个输入中指定的命令。它将输出到管道,而不是标准输出。第二个子进程将运行第二个输入中指定的命令。它将从管道中获取输入,而不是标准输入。父进程将等待其两个子进程完成,然后整个过程将重复。当输入“@”符号作为第一个命令时,执行将停止。以下是我的代码: #include <unistd.h

前提: 编写一个程序,向用户查询两个输入字符串。每个输入字符串都应该是一个unix命令,并且允许有参数。例如,输入1可以是
ls-l
,输入2可以是
more
。然后程序将创建一个管道和两个子进程。第一个子进程将运行第一个输入中指定的命令。它将输出到管道,而不是标准输出。第二个子进程将运行第二个输入中指定的命令。它将从管道中获取输入,而不是标准输入。父进程将等待其两个子进程完成,然后整个过程将重复。当输入“@”符号作为第一个命令时,执行将停止。以下是我的代码:

#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int main(){

    /* Program Termination Symbol */
    const char terminate = '@';

    /* String delimiter */
    const char delimiter = ' ';

    /* Pipe file ID's */
    int fileID[2];

    /* Parent ID's */
    int pid1, pid2;

    /* String token */
    char * token, * token2;

    /* User input */
    char * user_input, line[100];

    user_input = (char *) malloc(100);

    /* Unix Commands */
    char * command1[10], *command2[10];

    for (int i=0; i<10; i++)
    {
    command1[i] = (char *)malloc(100*sizeof(char));
    command2[i] = (char *)malloc(100*sizeof(char));
    }

    /* Begin main program logic */

    printf("Please enter the first command: \n");

    user_input = gets(line);

    while (user_input[0] != terminate)
    {
    token = (char *) malloc(100*sizeof(char));

    for (int i=0; i<10; i++)
        {
        if (i == 0)
        {
        token = strtok(user_input, &delimiter); 
        } else {
        token = strtok(NULL, &delimiter);
        }

        if (token != NULL)
        {
        strcpy(command1[i], token);
        } else {
        command1[i] = 0;
        }
        }

    printf("Please enter the second command: \n");  
    user_input = gets(line);

    token2 = (char *) malloc(100*sizeof(char));

    for (int i=0; i<10; i++)
    {
        if (i == 0)
        {
        token2 = strtok(user_input, &delimiter);
        } else {
        token2 = strtok(NULL, &delimiter);
        }

        if (token2 != NULL)
        {
        strcpy(command2[i], token2);
        } else {
        command2[i] = 0;
        }
    }   


    /* Pipe and execute user commands */

    /* Create pipe */
    pipe(fileID);

    /* Create child processes */

    pid1 = fork();

    if (pid1 != 0)
    {
        pid2 = fork();
    }

    /* First child process */
    if (pid1 == 0)
    {
        dup2(fileID[1], 1);
        execvp(command1[0], command1);
    }

    /* Second child process */
    if (pid2 == 0)
    {
        dup2(fileID[0], 0);
        execvp(command2[0], command2);
    }   

    /* Wait for children to terminate */
    wait(&pid1);
    wait(&pid2);

    /* Repeat */
        printf("Please enter the first command: \n");
    user_input = gets(line);
    }

    return 0;
}
…然后它就锁起来了。如果删除第二个等待,则输入/输出为

Please enter the first command:
ls
Please enter the second command:
more
Pipe
Pipe.c
Pipe.c~
Please enter the first command:
ls
Please enter the second command:
more
Pipe
Pipe.c
Pipe.c~
Please enter the first command:
(I hit enter, nothing else will work)
Segmentation fault
有人有什么建议吗?这显然与等待这两个过程有关,但我不知道如何处理它



这个程序现在是100%功能性的-非常感谢大家的帮助!堆栈溢出是internet上最好的资源之一。非常感谢大家花时间查看我的代码并给出建议

有几件事。不确定他们是你的问题的原因,但在提交作业之前还是要考虑。

  • 我认为你没有正确地使用
    wait
    。根据,它不接受pid指针作为参数

  • 每次在循环中调用malloc以获取
    token
    token2
    ,但我没有看到相应的内存释放

  • 您已经编写了单个单片函数。良好的编码实践建议将其分解为一系列子例程

  • 最后,可能与第3点有关,以下两行代码在代码中出现两次。同样,这不是一个错误,而是不必要的重复和不雅

    printf(“请输入第一个命令:\n”); 用户输入=获取(行)


  • 首先,您也在从子进程调用
    wait
    [编辑:不,您不是,因为每个子进程都调用execvp]

    另外,
    wait
    不会将指针指向子进程的pid,而是指向进程状态将写入其中的变量(这意味着您将丢弃子进程的pid)


    最后,尝试使用带有“WNOHANG”选项的
    waitpid
    。它不会挂起,您可以在执行其他操作时将这两个进程都放在一个循环中,并且可以通过检查状态变量来检查子进程是否已退出
    man waitpid

    我同意torak所说的一切,但为了解决您的问题,您需要关闭管道。我认为你是在“吊死”,因为管道还开着

    所以在父级中,就在“等待”之前,我会关闭管道

    close(fileID[0]);
    close(fileID[1]);
    wait(&pid_status);
    wait(&pid_status);
    
    然后,在每次execvp之前,我会关闭孩子不会使用的管道的末端:

    close(fileID[0]);
    dup2(fileID[1], 1);
    execvp(command1[0], command1);
    
    
    close(fileID[1]);
    dup2(fileID[0], 0);
    execvp(command2[0], command2);
    

    那应该可以解决你的绞刑问题。除了torak提出的建议外,我还建议使用fgets而不是get来防止缓冲区溢出。

    Yes wait使用一个名为status的int*值。考虑使用WITPID,把PID、状态和选项作为争论。我现在大概应该知道了,但是有人能解释一下为什么我的答案结尾的代码不正确。你记得缩进这行吗?”Hugh Brackett:是的,两行中的每一行有四个缩进空格。关于没有释放内存,你是非常正确的-谢谢你指出这一点,我已经添加了这一点。关于单片实现,您也是正确的。现在我有了一个工作程序,我可能会回去清理它。你只需要在管道末端等待孩子。@PeterRitchie请注意,家庭作业标签已被弃用(请阅读说明)。谢谢。我相信我实际上没有从子进程调用wait-当遇到execvp语句时,当前进程中的其余代码不会执行。它将替换为execvp调用中的代码。至少,这是我对它的理解。至于使用pid作为传递值…我不关心等待返回的状态,所以我传递了一个不再需要的值。根据我的理解,wait将只在一个子进程上等待-无法使用该函数控制哪个进程。确实,execvp停止子进程的执行。我将修改我的答案。至于pid,您现在可能不需要它,但是为不同的目的重用变量是非常糟糕的,并且您可能最终会以稍后需要pid的方式更改程序。所以,特别是对于家庭作业,你应该使用不同的变量来表示状态。尝试节省变量名没有任何意义。waitpid函数允许您定义要等待的特定pid。看看它的主页,你是对的,这是一个糟糕的做法——我应该再做一个变量。现在,它不像一个int变量是一个非常必要的空间,应该不惜一切代价保留它。我改变了我的程序来做这个。谢谢你的建议!精确地可读性非常重要:)这解决了绞刑问题,非常感谢。该程序现在(大部分)运行正常。这项任务快把我逼疯了。上周我们讨论了内存管理,所以我确信我们的编程任务会涉及到这一点……但是,没有——从左外角看,是管道。