0

When I run this code, it prints "hello world" 20 times. As per my understanding it should be print it 32 times. Also, the newline gets printed differently with each run. I don't understand this. Please help.

int
main(int argc, char** argv){
    if(fork() || fork())
        fork();
    if(fork() && fork())
        fork();
    printf("\nhello world");
    return 0;
}
10
  • 1
    This is a perfect example of why you shouldn't be using fork() to begin with, it is 1980s programming. Use threads, or if you really must create another process, then create a separate program, with it's own source code and start up that program as a different process with the appropriate API call. Commented Feb 18, 2016 at 7:21
  • 2
    Short circuit evaluation will affect the outcome. Explaining the exact count is waste of time since no sensible person would write code like this. Commented Feb 18, 2016 at 7:26
  • 2
    @Lundin Almost any function can be used incorrectly and that should not be taken for a reason not to use that function. There are perfect valid use cases for fork - the only thing you need to make sure when using a function is that you really understand it which may be why the question was asked. Commented Feb 18, 2016 at 7:36
  • 1
    The code is wrong, because every call to fork should keep and test its result. Once you have converted your code to do that, it would be much clearer. Commented Feb 18, 2016 at 7:40
  • 3
    @Lundin it's flat out silly to say that one shouldn't use fork because it's "1980s programming." I have no idea what that means, but fork, when used correctly, is the correct API to startup a different process on most UNIX-derived systems. It can be followed by some variant of exec if you need the new process to use some other executable. So let's be clear. The problem the OP has isn't fork. It's not using the API properly. Commented Feb 18, 2016 at 7:48

3 Answers 3

4

To understand you will have to disect both constructs. First the construct

if( fork() || fork() )
    fork();

or written in another way by unfolding the short-circuit or:

if( !fork() )
    if( !fork() )
        goto not_taken;
fork();
not_taken:

or without goto's

if( !fork() ) {
    if( fork() )
        fork();
}
else
    fork();

will five-fold the number of processes. This is because first the original process forks, then in the child as the fork will return zero it will fork again (short-circuit or). Then if any of these returned non-zero (that is the parent of the fork) it will fork again - this happens to be done in the parent process and it's child. That is the forks in the conditions will be called once and the last fork will be run once.

Now for the second construct:

if( fork() && fork() )
    fork();

or with unfolding short-circuit and:

if( fork() )
    if( fork() )
        fork();

the process count will four-fold. The reason is that first fork will be run in the parent process and if that returns non-zero (ie the parent process) the second fork will be called and if that to returns non-zero the last will. So here all three forks are called in the original process - which means that it's called three times.

So first construct will make them five processes and the second will then for each process create three more. That means we will have 5*4 processes.

The reason you don't get consistent newlines is probably most due to printf buffering. The printf will only immediately print out a newline, and then write the rest of the data when it terminates, this means that they print the string in two step. We have 20 processes that first prints a newline and then prints "hello world" concurrently - the order between what the different processes prints cannot be guaranteed.

A minor possibility is the very fact that the actual printout aren't required to be atomic. That is one process may write "hell", and then a second which already written "hello " gets to write which may be "world" - which would result in "hellworld" instead.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the help. Got it now. Really appreciate your help.
0

Let's count how many times each fork is called. In this block there are 3 forks:

if(fork() || fork())
    fork();

The 1st fork is called 1 time, by the first process.

The 2nd fork is called only 1 time, by the second process. (first process doesn't reach it)

The 3rd fork is called 2 times, by both first and second processes.

So, at this point you already have 5 processes.

For this block there are another 3 forks:

if(fork() && fork())
    fork();

The 1st fork is called 1x 5 times. Here, the forked child process goes to printf directly.

The 2nd fork is called 1x 5 times. Still, the forked child process goes to printf.

The 3rd fork is called 1x 5 times.

So you have 20 in total.

Comments

0

This is much easier if you evaluate the two if constructs separately. Count the number of processes created in the first and multiply it by the number created in the second. The result is the total number of processes and the times the printf call is called.

(We are assuming fork calls will not fail.)

The first if statement is shows by this handy chart, where columns are forks, rows are processes. forks - f1, f2, f3
processes - c0, c1, ... ,c4
xN - marks the creation of a process where N is the index of the created process
. - marks the process creation
_ - process exists and does nothing
(no character means the process doesn't exist at that point)

        f1  f2  f3
c0  _   x1  _   x2  _
c1      .   x3  x4  _
c2              .   _
c3          .   _   _
c4              .   _

At this point 5 processes exist, 4 additional were created. The next chart shows the second if statement, but only for one process:

        f1  f2  f3  
c0  _   x1  x2  x3  _   
c1      .   _   _   _
c2          .   _   _
c3              .   _

This if statement, creates 3 additional processes, so 4 exist. But remember we had 5 processes before, not just one. So both if statements together create 5 x 4 processes, 20 in total.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.