0
#include "csapp.h"

int main()
{
        int i;

        for (i = 0; i < 2; i++)
                fork();
        printf("hello\n");
        exit(0);
}
/*
 *                .------------------------
 *                |
 *                |
 *                |
 *    .-----------.------------------------
 *    |
 *    |
 *    |           .------------------------
 *    |           |
 *    |           |
 *    |           |
 *    .-----------.------------------------
 *   fork        fork
 *   i=0         i=1
 */

In the process pic, it seems the code will print "hello" four times. Why print 'hello' three times in my centos?

leonzai
  • 53
  • 4
  • 1
    @eonzai You created two processes ( in the loop ) together with the main process. So printf will be called three times. – Vlad from Moscow Jul 25 '19 at 10:04
  • @VladfromMoscow I count three processes together with the main process – Ctx Jul 25 '19 at 10:06
  • @Ctx For i equal to 0 - one process, for i equal to 1 - second process. Where is there the third process? – Vlad from Moscow Jul 25 '19 at 10:07
  • 2
    @VladfromMoscow The second loop iteration is performed by _two_ processes – Ctx Jul 25 '19 at 10:07
  • @Ctx Does the code of a created process include the loop? – Vlad from Moscow Jul 25 '19 at 10:12
  • 1
    After the `i == 0` iteration, there are two processes. After the `i == 1` iteration, there are 4 processes. Add more printing with the PID in each line of output, and record and print the return value from `fork()` too. – Jonathan Leffler Jul 25 '19 at 10:19
  • @VladfromMoscow Yes, of course, 3 iterations would yield 7 extra processes, 4 => 15 etc. (exponential) – Ctx Jul 25 '19 at 10:20
  • Was one of `fork` failed? Would this show extra output `if(fork() != 0) printf("%s\n", strerror(errno));` ? – Renat Jul 25 '19 at 10:22
  • I can see 4 processes. Maybe u didn't get the expected result because multiple processes are trying to write to stdout at the same time. Try some kind of sleep based on pid to be sure. – Emil Terman Jul 25 '19 at 10:41

2 Answers2

5

Unless there's something weird in your csapp.h header, you should be getting four lines printed out because after the first iteration of the loop (i == 0 before the increment), the fork() creates two processes, and on the second iteration (i == 1 before the increment), each of those two processes executes fork() to create two more processes.

When this code is run on macOS 10.14.6, I get 4 lines saying hello:

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

int main(void)
{
        int i;

        for (i = 0; i < 2; i++)
                fork();
        printf("hello\n");
        exit(0);
}

Output:

hello
hello
hello
hello

I'd instrument it far more than the bare minimal code shown in the question, though — like this:

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

int main(void)
{
    int i;
    printf("P0: PID = %d, PPID = %d\n", (int)getpid(), (int)getppid());
    fflush(stdout);

    for (i = 0; i < 2; i++)
    {
        int pid = fork();
        printf("PF: i = %d, PID = %d, PPID = %d, fork = %d\n",
                i, (int)getpid(), (int)getppid(), pid);
        fflush(stdout);
    }
    printf("Hello: PID = %d, PPID = %d\n", (int)getpid(), (int)getppid());
    return(0);
}

Note the copious use of fflush() to avoid the printf() anomaly after fork().

An example output I got from this was:

P0: PID = 5039, PPID = 916
PF: i = 0, PID = 5039, PPID = 916, fork = 5042
PF: i = 1, PID = 5039, PPID = 916, fork = 5043
Hello: PID = 5039, PPID = 916
PF: i = 0, PID = 5042, PPID = 5039, fork = 0
PF: i = 1, PID = 5043, PPID = 1, fork = 0
Hello: PID = 5043, PPID = 1
PF: i = 1, PID = 5042, PPID = 1, fork = 5044
Hello: PID = 5042, PPID = 1
PF: i = 1, PID = 5044, PPID = 5042, fork = 0
Hello: PID = 5044, PPID = 5042

Note that two of the processes reported PPID = 1 because the parent process (5039) had already exited. It would be feasible/sensible to add a loop to wait for children to die and report their exit statuses.

#include <sys/wait.h>

…

int corpse;
int status;
while ((corpse = wait(&status)) > 0)
{
    printf("WT: PID = %d, PPID = %d, child %d exited 0x%.4X\n",
           (int)getpid(), (int)getppid(), corpse, status);
    fflush(stdout);
}

What do you get on CentOS?

I'm running the program from the command line in a terminal window. If you're running this from an IDE or something, you might be losing the output from the orphaned processes. Adding the wait() loop would prevent the first process from exiting until all (both) its children had exited, leading to an orderly display of the 4 "Hello" lines. I've reworked the output formatting so it is easier to read the output.

#include <stdio.h>
#include <sys/wait.h>
#include <unistd.h>

int main(void)
{
    int i;
    printf("P0: PID = %5d, PPID = %5d\n", (int)getpid(), (int)getppid());
    fflush(stdout);

    for (i = 0; i < 2; i++)
    {
        int pid = fork();
        printf("PF: PID = %5d, PPID = %5d, i = %d, fork = %5d\n",
                (int)getpid(), (int)getppid(), i, pid);
        fflush(stdout);
    }

    printf("hello\n");
    printf("HO: PID = %5d, PPID = %5d\n", (int)getpid(), (int)getppid());
    fflush(stdout);

    int corpse;
    int status;
    while ((corpse = wait(&status)) > 0)
    {
        printf("WT: PID = %5d, PPID = %5d, child %5d exited 0x%.4X\n",
                (int)getpid(), (int)getppid(), corpse, status);
        fflush(stdout);
    }

    printf("EX: PID = %5d, PPID = %5d\n", (int)getpid(), (int)getppid());
    return(0);
}

Sample output (no orphaned processes):

P0: PID =  5245, PPID =   916
PF: PID =  5245, PPID =   916, i = 0, fork =  5248
PF: PID =  5248, PPID =  5245, i = 0, fork =     0
PF: PID =  5245, PPID =   916, i = 1, fork =  5249
hello
HO: PID =  5245, PPID =   916
PF: PID =  5248, PPID =  5245, i = 1, fork =  5250
PF: PID =  5249, PPID =  5245, i = 1, fork =     0
hello
HO: PID =  5248, PPID =  5245
hello
HO: PID =  5249, PPID =  5245
EX: PID =  5249, PPID =  5245
PF: PID =  5250, PPID =  5248, i = 1, fork =     0
hello
HO: PID =  5250, PPID =  5248
EX: PID =  5250, PPID =  5248
WT: PID =  5245, PPID =   916, child  5249 exited 0x0000
WT: PID =  5248, PPID =  5245, child  5250 exited 0x0000
EX: PID =  5248, PPID =  5245
WT: PID =  5245, PPID =   916, child  5248 exited 0x0000
EX: PID =  5245, PPID =   916
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
1

Maybe a fork failed or there is a conflict among the printf. On ideone it correctly prints 4 times.

enter image description here

Giampietro Seu
  • 786
  • 9
  • 16