8

I have a simple code to test the fork() function.

    #include<stdio.h>
    #include<unistd.h>
    #define MAX_COUNT 10
    void main(void)
    {
        pid_t pid;
        int i;
        fork();
        pid = getpid();
        for(i = 1; i <= MAX_COUNT; i++)
        {
            printf("PID = %d, i = %d\n", pid, i);
        }
    }

It didn't work as I expected.

My expectation is: parent's result and child's result appear alternately. Can someone explain this and teach me how to fix it? Thanks!

    PID = 3663, i = 1
    PID = 3663, i = 2
    PID = 3663, i = 3
    PID = 3663, i = 4
    PID = 3663, i = 5
    PID = 3663, i = 6
    PID = 3663, i = 7
    PID = 3663, i = 8
    PID = 3663, i = 9
    PID = 3663, i = 10
    PID = 3664, i = 1
    PID = 3664, i = 2
    PID = 3664, i = 3
    PID = 3664, i = 4
    PID = 3664, i = 5
    PID = 3664, i = 6
    PID = 3664, i = 7
    PID = 3664, i = 8
    PID = 3664, i = 9
    PID = 3664, i = 10
TryinHard
  • 4,078
  • 3
  • 28
  • 54
Tai Nguyen
  • 115
  • 7
  • 7
    The two processes operate independently so you cannot expect any specific ordering once the fork has occured (it depends on OS scheduling). If you want a specific ordering you must explicitly do that yourself with synchronisation mechanisms. For example, wait, semaphores, mutexes, pipes, etc. – kaylum Jul 03 '15 at 03:49
  • I meant ordering between the processes of course. Ordering within the process is well defined naturally. – kaylum Jul 03 '15 at 03:51
  • try adding `sleep(1);` to your for loop. – QuestionC Jul 03 '15 at 04:07
  • @QuestionC that's not a very good idea. It will return the process to the scheduler bu there is no assurance the scheduler will alternate between processes. – Eli Algranti Jul 03 '15 at 04:09
  • If your objective is to just test `fork()` and poke around, throwing sleeps around is pretty normal practice. I believe *alternatingly* really means non-sequentially in this context. – QuestionC Jul 03 '15 at 04:16
  • What lead you to expect guarantees from the scheduler? – Charles Duffy Jul 03 '15 at 04:22
  • @QuestionC point taken – Eli Algranti Jul 03 '15 at 04:32
  • Possible duplicate of [fork() does not run parallel](https://stackoverflow.com/q/64721030) - perhaps you ran with output to a pipe, so I/O buffering resulted in two large write system calls, not multiple small writes that could interleave separately. Run it on a terminal for more iterations, and/or with `fprintf(stderr, ...)` – Peter Cordes Apr 21 '22 at 02:23

2 Answers2

11

The explanation is simple. Scheduling of processes is up to the kernel. If this is a single core processor then in this run it decided to suspend the child execution and allow the parent process to run first. The parent ran for a few loops before being suspended in favor of the child, and so forth.
In a multiprocessor system both process can run in tandem but the console device will alternate the output depending on timing of interrupts.

There is no assurance a different run will result in the same output. There is also no assurance that different kernel version won't do something else.

If you want the processes to alternate between loops now is the time to learn interprocess communication.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
Eli Algranti
  • 8,707
  • 2
  • 42
  • 50
  • In general, you can expect the kernel to be 'fair' when scheduling processes. That means that, if the parent and child are run for a long time, they will both get roughly the same amount of processing time and neither will have to wait too long between activations. Of course, the time scales considered here are far greater than a couple of loop iterations. – MicroVirus Jul 03 '15 at 09:46
2

The main process isn't giving up control immediately, and the for loop executes so fast that it is done before the second process gets scheduled. When I execute your code I get non-sequential prints, but the behavior is system dependent.

It sometimes helps to throw sleep() commands around when you're playing with fork(). Try this code...

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

#define MAX_COUNT 10
int main(void)
{
  pid_t pid;
  int i;
  fork();

  pid = getpid();

  srand(pid); // Make sure each process has a different seed

  for(i = 1; i <= MAX_COUNT; i++)
  {
    printf("PID = %d, i = %d\n", pid, i);

    // Sleep 1-3 seconds.
    unsigned int sleep_seconds = rand() % 3 + 1;
    sleep(sleep_seconds);
  }
}
QuestionC
  • 10,006
  • 4
  • 26
  • 44