0
votes

I am trying to better understand fork(), waitpid() and child/parent processes, however there are some strange behaviors I have encountered with the following code:

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

int main(void){ // Main

    int status;
    pid_t wPID, cPID;
    printf("[%i] Hi I am the parent and I am about to create a child...\n", getpid());
    fflush(0); 
    pid_t childPID = fork();

    if (childPID >= 0){
        if(childPID == 0){ //child process
            cPID = getpid();
            printf("[%i] %i\n", getpid(), cPID );
            printf("[%i] Hi, I am the child process...\n", getpid() );
            sleep(1);

            for(int i = 0; i<3; i++){
                printf("[%i] %i\n", getpid(), i);
            }
            exit(0);
        }
        else{ //parent
            printf("[%i] %i\n", getpid(), cPID );
            wPID = waitpid(cPID, &status, 0);
            printf("[%i] value returned by waitpid: %i\n", getpid(), wPID);

            if (WIFEXITED(status))
                printf("[%i] child exited, status=%d\n", getpid(), WEXITSTATUS(status));
            else if (WIFSIGNALED(status))
                printf("[%i] child killed (signal %d)\n", getpid(), WTERMSIG(status));
            else if (WIFSTOPPED(status))
                printf("[%i] child stopped (signal %d)\n", getpid(), WSTOPSIG(status));
            else  /* Non-standard case -- may never happen */
                printf("Unexpected status (0x%x)\n", status);
            return 0; 
        }
    }
    else{
        printf("\n Fork failed, quitting!\n");
        return 2;  // error
    }
}

console output:

$ ./waitpidexample 
[6103] Hi I am the parent and I am about to create a child...
Error: No child processes
[6103] 1540418008
[6103] value returned by waitpid: -1
[6103] child killed (signal 54)
[6104] 6285
[6104] Hi, I am the child process...
[6104] 0
[6104] 1
[6104] 2

I believe my issue is in the cPID variable being used in waitpid()...

there is some sort of scope issue happening here, as it evaluates to different values in the child / parent.

How am I supposed to get the correct child process id for use in waitpid()?

Why is the code after my waitpid() being executed before the code in the child process?

2
The child PID is in childPID, not cPID...Oliver Charlesworth
The output you show doesn't match the program you show. There's nowhere in the program where you print Error: No child processes. Although that could be because of the undefined behavior you have when doing fflush with a null pointer.Some programmer dude
Also, when a function like waitpid returns with an error (in the case of many system functions indicated by a return of -1) then you need to check errno to figure out what happened. And you need to do it immediately, you can't call any function which might alter errno in between.Some programmer dude
Lastly, and what seems to be your misunderstanding, is that when a process forks a child process, the memory of the parent is copied into the child. Once that is done the memory of the parent and child are separate, there's no sharing at all. If you want to share memory, then either use shared memory, or use threads.Some programmer dude
you are right I threw a perror("Error") there to see what I was getting but didnt put that up on the stack overflow code here. It wont let me edit it anymore but its not a huge issue.cblanto7

2 Answers

5
votes

cPID is only changed in the child process. When you call fork, a complete copy is made (functionally, in reality until something is changed, the memory is shared). This means that when cPID is written in the child (first branch) the parent does not see it. Change the references to cPID in the parent (second branch) to childPID (assigned from fork()):

else{ //parent
    printf("[%i] %i\n", getpid(), childPID );
    wPID = waitpid(childPID, &status, 0);
    printf("[%i] value returned by waitpid: %i\n", getpid(), wPID);
    if (WIFEXITED(status))
        printf("[%i] child exited, status=%d\n", getpid(), WEXITSTATUS(status));
    else if (WIFSIGNALED(status))
        printf("[%i] child killed (signal %d)\n", getpid(), WTERMSIG(status));
    else if (WIFSTOPPED(status))
        printf("[%i] child stopped (signal %d)\n", getpid(), WSTOPSIG(status));
    else  /* Non-standard case -- may never happen */
        printf("Unexpected status (0x%x)\n", status);
        return 0;
}

Also, I recommend using braces after all your if statements

Run Order

fork() does not define which process gets run first, just that there is now a child process (in which it returns 0) and a parent process (in which it returns the child's PID). The child process will be identical to the parent, except for the return value of fork(). Sometimes, the parent goes first, sometimes the child does. It is non-deterministic.

2
votes

In the parent process, cPID is never initialized. The variables in the parent and child are separate from each other, so a variable change in the child is not visible in the parent and vice versa.

The parent already has the child pid in childPID, so use that instead.

printf("[%i] %i\n", getpid(), childPID );
wPID = waitpid(childPID, &status, 0);