简体   繁体   English

read()块时如何退出while循环

[英]How to exit while loop when read() blocks

In a problem given by university we have to pipe from a parent process(P1) to its child P2, and afterwards P2 must pipe to another child of P1, the other child is P3. 在由大学给出的一个问题,我们必须pipe从父进程(P1)到其子P2,之后P2必须管P1的另一个孩子,另一个孩子是P3。 Both P2 and P3 are to be written in c and made into executable files. P2和P3都将用c编写并制成可执行文件。 They will then by exec ed by child processes in P1. 然后,它们将由P1中的子进程exec

P1 writes the numbers 1 to 10000 to stdout , P2 reads them through its stdin , removes the numbers divisible by 2, and writes the result to its stdout . P1将数字1到10000写到stdout ,P2通过其stdin读取它们,除去被2整除的数字,并将结果写到其stdout P3 reads those numbers through its stdin , filters out the results that are divisible by 3, and writes everything to a file. P3通过其stdin读取这些数字,过滤出可被3整除的结果,并将所有内容写入文件。

I have managed to implement absolutely everything, but my child processes do not end. 我已经设法实现了所有事情,但是我的子进程并没有结束。 The reason for this, I believe, is that I have used the following method to read the input in each child: 我相信,这样做的原因是,我已经使用以下方法读取每个孩子中的输入:

while(n=read(0, &i, sizeof(i))>0)

The problem here, as I understand it, is that read blocks when it doesn't get any bytes. 据我了解,这里的问题是, read没有任何字节时就会阻塞。 As P1 writes the 10000 numbers using: 当P1使用以下命令写入10000个数字时:

for(i=1; i<=10000; i++){
        write(1, &i, sizeof(i));
    }

Neither child process ever has any reason to believe that no more data is coming its way. 这两个子进程都没有任何理由相信不会再有任何数据在发送。 Therefore, each read simply blocks waiting for a byte that will never come. 因此,每次read仅阻塞等待一个永远不会到来的字节。

Can anyone suggest a way to overcome this roadblock? 谁能提出克服这一障碍的方法?

The code of each process is as follows: 每个过程的代码如下:

Parent: 上级:

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/types.h>
#include<string.h>
#include<sys/wait.h>
#include <errno.h>
#include <sys/stat.h>
#include <fcntl.h>


int main()
{
        // pipe to send input string from parent
        // Child prints to file 
        int fd1[2];  // Used to store two ends of first pipe
        int fd2[2];  // Used to store two ends of second pipe

    //variables
    int n, i, status1, status2;
    char *args1[]={"./Div2",NULL};
    char *args2[]={"./Div3",NULL};


    //child process ids
        pid_t pid1, pid2;

    //open pipe 1
        if (pipe(fd1)==-1)
        {
            fprintf(stderr, "Pipe 1 Failed" );
            return 1;
        }
    //open pipe 2
    if (pipe(fd2)==-1)
        {
            fprintf(stderr, "Pipe 2 Failed" );
            return 1;
        }

    //create child 1    
    pid1 = fork();  
    if(pid1<0){
        printf("Error creating child1\n");
        return(1);
    }
    if(pid1==0){ //child1
        if(close(fd1[1])<0){ //child does not write to pipe 1
            error();
        }
        if(close(fd2[0])<0){ //child does not read from pipe 2
            error();
        }
        dup2(fd1[0], 0); //redirect stdin
        dup2(fd2[1], 1); //redirect stdout
            execvp(args1[0],args1);
        if(close(fd1[0])<0){ //close used pipe
            error();
        }
        if(close(fd2[0])<0){ //close used pipe
            error();
        }
        exit(0);
    }

    pid2=fork();
    if(pid2<0){
        printf("Error creating child2\n");
        return(1);
    }
    if(pid2==0){ //child2
        if(close(fd1[0])<0){ //child does not use pipe 1
            error();
        }
        if(close(fd1[1])<0){ 
            error();
        }
        if(close(fd2[1])<0){ //child does not write to pipe 2
            error();
        }
        dup2(fd2[0], 0); //redirect stdin
        execvp(args2[0], args2);
        if(close(fd2[0])<0){ //close pipe after use
            error();
        }
        exit(0);
    }


    //parent
    //parent doesn't read from the pipe
    if(close(fd1[0])<0){
    error();
    }
    if(close(fd2[0])<0){
    error();
    }
    if(close(fd2[1])<0){
    error();
    }
    dup2(fd1[1], 1); //redirect stdout
    for(i=1; i<=10000; i++){
        write(1, &i, sizeof(i));
    }
    if(close(fd1[1])<0){
    error();
    }
    int returnedPID1=waitpid(pid1, &status1, 0);
    if(returnedPID1==pid1){
    printf("Parent waited for child as predicted\n");
    }
    int returnedPID2=waitpid(pid2, &status2, 0);
    if(returnedPID2==pid2){
    printf("Parent waited for child as predicted\n");
    }
    _exit(0);

}

P2 (includes excluded) P2(不包括在内)

int main()
{
    int n;
    int i;
    while((n=read(0, &i, 4))>0){
        if((i%2)!=0){
            write(1, &i, sizeof(i));
        }   
    }
    return;
}

P3 P3

int main()
{
    int n;
    int i;
    char tmp[12] = {0x0};
    char *arg[]= {"/home/eric/Documents/pr3/test.txt"};
    int fp = open(arg[0], O_WRONLY|O_CREAT|O_TRUNC, 0666);
        if(fp<0){
            printf("Error opening file\n");
            _exit(1);
        }

    while((n=read(0, &i, 4))>0){
        if((i%3)!=0){
            sprintf(tmp,"%11d", i);
            write(fp, tmp, strlen(tmp));
        }   
    }
    return;
}

Thanks guys. 多谢你们。

Except in case of error, exec never returns. 除非出现错误,否则exec从不返回。 So when you write: 所以当你写:

    execvp(args1[0],args1);
    if(close(fd1[0])<0){ //close used pipe
        error();
    }

you are wrong to expect the file descriptor to be closed. 您期望文件描述符关闭是错误的。 Close them before you exec. 执行前将其关闭。 They are getting left open. 他们被打开。 Although in your particular case the problem is that the parent never closes fd 1. The parent has two file descriptors that are writing into the pipe ( fd[1] and 1 ), and you need to close them both before the child reading the pipe will finish. 尽管在您的特定情况下,问题在于父级永远不会关闭fd1。父级有两个正在写入管道的文件描述符( fd[1]1 ),您需要在孩子读取管道之前关闭它们两个即将完成。

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

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