简体   繁体   中英

How to make a UNIX pipe prompt for user input correctly?

I am trying to have UNIX pipes correctly prompt for user input. I have to create 3 child processes using a single pipe. Each child process asks the user to enter an integer and writes it to the pipe. The parent process displays all three integers as well as the processid's of the process that wrote each to the pipe.

#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <unistd.h>

int main(int argc, char argv[]) {
    int input = 0;
    int pd[2];
    int i =0;
    int buffer[100];
    int output = 0;

    if (pipe(pd) == - 1) {
        fprintf(stderr, "Pipe Failed");
    }

    for (i=0; i<3; i++) {
        if (fork() == 0) { // child process
            printf("\nMy process id is: %d", getpid());
            printf("\nEnter an integer: ");  
            scanf("%d", &input);
            if (write(pd[1], &input, sizeof(int)) == -1) {
                fprintf(stderr, "Write Failed");
            }
            return (0); // Return to parent. I am not really sure where this should go 
        } // end if statement
    } // I am not quite sure where the for loop ends

    // Parent process
    close(pd[1]); // closing the write end

    for (i = 0; i < 3; i++) {
        if (read(pd[0], &output, sizeof(int) )== -1) {
            fprintf(stderr, "Read failed"); 
        }
        else {
            buffer[i] = output;
            printf("Process ID is: %d\n", pid);
        }
    } 
    printf("The numbers are %d, %d, %d", buffer[0], buffer[1], buffer[2]);
    return(0);
}

After editing, I now get as output:

My process id is: 2897
Enter an integer: My process id is: 2896
Enter an integer: 
My process id is: 2898
Enter an integer: 4
Process ID is: 2898
78
Process ID is: 2898
65
Process ID is: 2898
The numbers are 4, 78, 65

which is a lot closer but I am not yet sure how to make the parent wait for the child processes. When trying to print each number along with it's process id, only the most recent process id is getting printed.

All of the printf statements execute before the scanf statements so I can't type anything until it prompts 3 times.

Only one process can be talking to the user at any given time. You need to arrange so that child 2 doesn't do anything until child 1 is done, and so on. The simplest way to do this is to have the parent wait() for each child in succession, before forking off the next one. EDIT: That would look something like this:

for (i = 0; i < 3; i++) {
    pid_t pid = fork();
    if (pid == -1) {
        perror("fork");
        return 1;
    } else if (pid == 0) {
        // your existing child code goes here
    } else {
        // parent:
        int status;
        if (waitpid(pid, &status, 0) != pid) {
            perror("wait");
            return 1;
        } else if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
            fprintf(stderr, "child %d unexpected exit %d\n", i, status);
            return 1;
        }
    }
}

Since the amount of data written to the pipe is very short (less than PIPE_BUF bytes in total; PIPE_BUF is guaranteed to be at least 512), you can safely delay reading from the pipe until after all children have exited. This would not be the case if the children were sending back longer messages.

main returns an integer. Your return; statement inside the first loop should be return 0; and there needs to be another return 0; at the very end (after the final printf ).

Your first for loop ends right where it ought to end, ie after the nested if statement. You can put another set of curly braces around it - open brace right after the for (...) , close brace right where you have the // I am not quite sure comment - and lots of people would consider that better style, but you don't have to.

if (read(pd[0]), &output, sizeof(int) )== -1)
              ^ // this is wrong

your parenthesis are incorrect but I assume that's a typo.

You also update buffer only if read fails... It should be:

if (read(pd[0], &output, sizeof(int) )== -1) {
    fprintf(stderr, "Read failed");
}
else {
    buffer[i] = output;
}

There are many ways this code could be improved though. Look at other answers and compile your programs with warnings on (-Wall with gcc)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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