Concurrent Instruction Execution

 Published on 21 Apr 2024 .  Filed in Notes .  450 words

The system call fork() is used to create new process which is a exact copy of the caller/parent process and the created process is called child process.

Here is an illustration of creating processes using the fork() function:

  #include  <stdio.h>
  #include  <string.h>
  #include <unistd.h>
  #include  <sys/types.h>

  #define   MAX_COUNT  200
  #define   BUF_SIZE   100

  void  main(void)
  {
    pid_t  pid;
    int    i;
    char   buf[BUF_SIZE];

    fork();
    pid = getpid();
    for (i = 1; i <= MAX_COUNT; i++) {
      sprintf(buf, "This line is from pid %d, value = %d\n", pid, i);
      write(1, buf, strlen(buf));
    } 
  }

If the above program successfully executes up to the fork() function (marked with an arrow in the following figure):

     Parent
+_____________+
| main() {    |
|  fork();    | <===
|  pid = ...; |
|  ....;      |
| }           |
+_____________+

Then it will create a new process identical to the parent process, except the return value of the fork() function, which is different for the two processes. This value is set by the kernel as the result of the fork() call. This is why we say that the fork() function return twice:

     Parent                            Child
+_____________+                    +_____________+
| main() {    |                    | main() {    |
|  fork();    |                    |  fork();    |
|  pid = xxx; | <===               |  pid = xxx; | <===
|  ....;      |                    |  ....;      |
| }           |                    | }           |
+_____________+                    +_____________+

Since both processes have identical but separate address spaces, the variables set before the fork() call will have the same value in both processes. However, because each process has its own address space, changes to these variables are independent of each other. In other words, changing the variable defined in the parent process will not affect the variable in the child process.

After the fork() system call or after created a new process both processes continue the execution of the program. Since the new process is an exact copy of the caller process, they both execute the same instructions that can be found after the fork() call in our code.

As mentioned above, the fork() function will create an exact copy of the caller process with a different value in the pid variable. We can use this value to determine whether the process is the parent or the child:

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

  int main() {
      pid_t pid;

      pid = fork();

      if (pid < 0) {
             // Error handling
             fprintf(stderr, "Fork failed\n");
             return 1;
         } else if (pid == 0) {
             // This will executed by the child process
             printf("Child process: Returned value from fork() is %d\n", pid);
         } else {
             // This will executed by the parent process
             printf("Parent process: Returned value from fork() is %d\n", pid);
         }

         return 0;
  }