0

According to my knowledge, the child process executes first. Why the parent process was executed before the child and the parent was executed again? How did the execution process went from parent to child to parent again? And why should the pipe be closed? I tried the code without the close pipe statement and I got the same output.

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

void main(){
    
    int P1P2[2];
    int P2P1[2];
    pipe(P1P2);
    pipe(P2P1);
    int x,y;
    if(fork()){  // father
    
        close(P1P2[0]);
        close(P2P1[1]);
        printf("Enter one integer:");
        scanf("%d",&x);
        write(P1P2[1], &x, sizeof(x));
        read(P2P1[0], &y, sizeof(y));
        printf("Multiplication is %d\n", y);
    
    }
    else{   //  Child
        close(P1P2[1]);
        close(P2P1[0]);
        read(P1P2[0], &x, sizeof(x));
        y = x*x;
        write(P2P1[1], &y, sizeof(y));
        
    }
}

output:

abbas@abbas-VirtualBox:~/Desktop$ ./simplle
Enter one integer:4
Multiplication is 16
Ruli
  • 2,592
  • 12
  • 30
  • 40
  • 4
    *the child process executes first*. That's not a correct statement. It is up to the OS scheduler and you cannot assume one or the other. Unless you have explicit synchronisation in your code to affect the process ordering (which you don't at that point). – kaylum May 06 '21 at 22:04
  • 2
    Even if the child does execute first, it's going to block on the `read` until the parent writes into the pipe. (The pipe is your synchronization mechanism.) – William Pursell May 06 '21 at 22:16

3 Answers3

2

After calling fork, there are two processes that run independently from each other. The processor switches between them like it does with other separate processes, so you won't always get the same behavior. If you did want the parent to wait for the child to finish, you could use waitpid.

BE-Code
  • 83
  • 1
  • 6
1
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>

int main(void){
    
    int P1P2[2];
    int P2P1[2];
    pipe(P1P2);
    pipe(P2P1);
    int x,y;
    if( fork() > 0 ){  // parent
        close(P1P2[0]);
        close(P2P1[1]);
        printf("Enter one integer:");
        scanf("%d",&x);
        write(P1P2[1], &x, sizeof(x)); /* (2) */
        read(P2P1[0], &y, sizeof(y));  /* (3) */
        printf("Multiplication is %d\n", y);
    } else {   //  Child (or pipe error)
        close(P1P2[1]);
        close(P2P1[0]);
        read(P1P2[0], &x, sizeof(x)); /* (1) */
        y = x*x;
        write(P2P1[1], &y, sizeof(y));  /* (4) */
    }  
}

Suppose the child is running immediately after the fork, and the parent is not. The child will block on the read at (1), waiting for data. Since there is no data, it will yield the cpu. At some point in the future, the parent will be scheduled and will execute printf, scanf and write. After the parent has written into the pipe at (2), either the child or the parent may execute in any order. Eventually, the parent will block on the read at (3) and will not be able to proceed until the child writes at (4). So the pipe works to synchronize the processes.

William Pursell
  • 204,365
  • 48
  • 270
  • 300
0

According to my knowledge, the child process executes first. Why the parent process was executed before the child and the parent was executed again? How did the execution process went from parent to child to parent again? And why should the pipe be closed? I tried the code without the close pipe statement and I got the same output.

Your knowledge is not correct. You don't know who is going to be scheduled first, if the parent or the child. Both cases can happen. The parent is normally free to run after the system call has checked all possible errors, while the child still has to build a complete environment to run. So it is very possible for the parent to run first.

The execution normally get's like this. The parent calls fork() which in turn switches to kernel mode. Here, the parent process (there's still no child anywhere) checks all conditions necessary to create a child process, enough resources, not trespassing of limits, etc. and if everything gets ok, then it creates a new process entry in the processes table. Once this is done, the parent kernel code has all the elements to start running a second kernel thread and starts it, to execute the second part of the fork call, while the first (the parent process) already has the return code of the system call and is ready to run (this means that the child process will be executed, not failing to do that, but it doesn't need to be immediately). From this point on, the parent process can return from kernel mode with the child pid, and continue, while the child kernel has still to build enough context to run and be scheduled. This can happen very quickly, even before the scheduler has had the time to reschedule the parent again, so the conclussion is that you don't know which one is to continue executing user code first.

In respect to your second question, the order of execution from the fork() onwards depends on so many things that is actually unpredictable. Both are different processes and execute as soon as the system allows them to proceed.

In respect to the closing of the pipes, you can do it or you cannot.... as you prefer... but a pipe works passing all the data from the writer process to the reader, until the pipe gets its last close(2) When you fork()ed, the system passed of having two pipes, with four file descriptors to have 4 (two on the parent, two on the child) with a total of eight file descriptor (four readers and four writer descriptors, two for each process) (and this means that both writers, the parent process and the child process, need to close(2) the writing side of the pipe for the readers --again, both the father and the child-- to receive the corresponding EOF indicating that the other end has closed its side) This is of no concern to you (I mean, doesn't show any difference) because you have limited your protocol to just one message in each direction, and there's no EOF condition to be waited for.... but try extending your sample code to read from the pipe until it closes it side, and you will see the difference (in that case, without having closing your writer side, your process will block waiting for input, and no input is received because the other process has closed the descritptor and the only process waiting for input is the only process that can write on it).

Luis Colorado
  • 10,974
  • 1
  • 16
  • 31