Home > database >  Possible outputs using fork()
Possible outputs using fork()

Time:07-12

In the following code:

int num = 0;
void signal_hand(int sig) {
    signal(SIGUSR1, signal_hand);
    num  ;
    printf("num = %d\n", num);
}

int main() {
    signal(SIGUSR1, signal_hand);
    pid_t pid = getpid();
    kill(pid, SIGUSR1);
    pid_t child = fork();
    switch(child) {
        case -1:
            perror("fork");
            exit(1);
        case 0:
            num = 0;
            kill(pid, SIGUSR1);
            break;
        default:
            num = num   1;
            kill(pid, SIGUSR1);
            break;
    }
    return 0;
}

The output could be only:

num = 1  
num = 2  
num = 4  

or:

num = 1  
num = 3  
num = 4  

But I don't understand why, If the parent runs first so that after printing num = 1 then num = 3 and then if the child is running so that num = 0 and then printing num = 1, how it's possible that num will be 4, I don't get the 2 cases. (When the parent runs first and when the child runs first)

CodePudding user response:

In the beginning there is only one process with num set to 0. Afterwards your first signal arrives:

int main() {
    signal(SIGUSR1, signal_hand);
    pid_t pid = getpid();
    kill(pid, SIGUSR1);

This naturally increases num by 1 and prints it, as this is how you defined your signal handler. This is where num = 1 comes from.

Afterwards you call fork. The process is copied, along with most of its resources which includes memory. The variables reside in the memory of the process, which means that they are copied as well. So now you have 2 processes, each with its own copy of num which are independent on each other. Both copies of num are equal to 1 as this was the value at the time when fork was called. Additionally, each process will have a different PID - the original process will retain its PID that you saved in the main function in the pid variable, and the copy will have a new PID. Keep that in mind as it is important for the example.

Now, according to your switch statement, each copy of the process will call different code:

switch(child) {
    case -1:
        perror("fork");
        exit(1);
    case 0:
        num = 0;
        kill(pid, SIGUSR1);
        break;
    default:
        num = num   1;
        kill(pid, SIGUSR1);
        break;
}

The copy of the process will execute the branch of the switch statement under the case 0:. It will reset num to 0 - but only its own copy! The copy of the original process will not be touched as they are independent. Then, it will fire a signal in the original process, not in itself. This is cause you use the pid variable that contains the PID of the original process. This will cause the signal handler to run, again, in the parent, which increases the num variable by 1 and prints it. At the same time, the original process will run the default: branch of the switch statement, increasing its copy of num by 1 and firing another signal in itself.

These two signals are responsible for num = 3 or num = 2 as well as num = 4. The middle result will be different based on a race condition in your code. With how you have written your code, you do not know whether the parent executes num = num 1 or the child executes its kill first. If the increment is first, then the value will be 3, if the kill is first, the value will be 2.

  • Related