Child processes won't die in C program

2019-08-09 08:53发布

问题:

I'm writing a C program that parses input from STDIN into words, generates a number of sort processes specified by the numsorts variable, pipes the words in a round-robin fashion to each of the sort processes, and sends the output of the sorts to STDOUT.

My program works as desired and exits cleanly if the number of specified sort processes is 1, but the sort child processes don't die if the number of sort processes is greater than 1, and my program gets stuck waiting for them. The strangest part of this, to me, is that if I open up a separate terminal window and kill all of the children except 1, the last child immediately dies on its own and the program exits cleanly.

Here's my code for the parser (the pipe file descriptors are stored in a 2-dimensional array):

void RRParser(int numsorts, int **outPipe){ //Round Robin parser
    int i;
    char word[MAX_WORD_LEN];

    //Close read end of pipes
    for(i = 0; i < numsorts; i++){
        closePipe(outPipe[i][0]);
    }

    //fdopen() all output pipes
    FILE *outputs[numsorts];
    for(i=0; i < numsorts; i++){
        outputs[i] = fdopen(outPipe[i][1], "w");
        if(outputs[i] == NULL)
            printf("Error: could not create output stream.\n");
    }

    //Distribute words to them
    i = 0;
    while(scanf("%[^,]%*c,", word) != EOF){
        strtoupper(word);
        fputs(word, outputs[i % numsorts]); //round robin
        fputs("\n", outputs[i % numsorts]); //sort needs newline
        i++;
    }

    //Flush the streams:
    for(i=0; i < numsorts; i++){
        if(fclose(outputs[i]) == EOF)
            printf("Error closing stream.\n");
    }
}

Here's the code that generates the sort processes (PukeAndExit() just prints out the error message and exits):

int *spawnSorts(int numsorts, int **inPipe){
    //returns an array containing all the PIDs of the child processes
    //Spawn all the sort processes
    pid_t pid;
    int i; 
    int *processArray = (int *)malloc(sizeof(int) * numsorts);
    for(i = 0; i < numsorts; i++){ 
        switch(pid = fork()){
            case -1: //oops case
                    PukeAndExit("Forking error\n");
            case 0: //child case
                //Bind stdin to read end of pipe
                closePipe(inPipe[i][1]); //close write end of input pipe
                if(inPipe[i][0] != STDIN_FILENO){ //Defensive check
                    if(dup2(inPipe[i][0], STDIN_FILENO) == -1)
                        PukeAndExit("dup2 0");
                    closePipe(inPipe[i][0]); //Close duplicate pipe
                }
                execlp("sort", "sort", (char *)NULL);
               break;
            default: //parent case
                processArray[i] = pid;
        }
    }
    return processArray;
}

At the end of main(), here's the code that waits for the sort processes to die:

for(i=0; i<numsorts; i++){ //wait for child processes to die. 
    wait(NULL);
}

回答1:

Nevermind, I figured it out. The bug was actually in the function where I generated the pipes. As soon as I switched to creating the pipes in my spawnSorts process, everything worked. Previously, I was generating an array of pipes in a separate function. I'm not sure why this works now but it does.

Old generatePipes function:

int **generatePipesArray(int numpipes){ //returns a 2-dimensional array of pipes
        int **pipesArray = (int **) malloc(sizeof(int *) * (numpipes));
        int i;
        for(i = 0; i < numpipes; i++){
                pipesArray[i] = (int *) malloc(sizeof(int) * 2);
                createPipe(pipesArray[i]);
        }
        return(pipesArray);
}

New function:

int **generatePipesArray(int numpipes){ //returns an empty 2-dimensional array
        int **pipesArray = (int **) malloc(sizeof(int *) * (numpipes));
        int i;
        for(i = 0; i < numpipes; i++){
                pipesArray[i] = (int *) malloc(sizeof(int) * 2);
                //not creating pipes here anymore
        }
        return(pipesArray);
}

Code added to spawnSorts:

int *spawnSorts(int numsorts, int **inPipe, int **outPipe){
//returns an array containing all the PIDs of the child processes
//Spawn all the sort processes
pid_t pid;
int i; 
int *processArray = (int *)malloc(sizeof(int) * numsorts);
for(i = 0; i < numsorts; i++){
     //new code here:
    createPipe(inPipe[i]);