user5575937
user5575937

Reputation:

Creating as many processes you want with Fork()

I'm trying to get my head around the system call fork() and I'd like to create as many grandchild processes as I'd like. Basically all I want to achieve is:

1 parent process with -> 2 child processes -> each child -> has two child processes (which are a total of 4 grandchild processes from the parent).

              parent
          /           \
         /             \
    child1             child2
    /    \               /  \
   /      \             /    \
  /        \           /      \
g.child1  g.child2  g.child3  g.child4

So far I can get 3 out of the 4 grandchild but I'm also getting a new child from one of the grandchilds. This is the output I'm getting so far:

Process Pid: 5960 PPid: 5958 (position: 1).
Process Pid: 5959 PPid: 5958 (position: 0).
Process Pid: 5962 PPid: 5959 (position: 0).
Process Pid: 5961 PPid: 5960 (position: 1).
Process Pid: 5963 PPid: 5961 (position: 1).
Process Pid: 5964 PPid: 5960 (position: 1).

Any tips?

Thank you

#include <unistd.h>
#include <stdlib.h> 
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>

#define NUM_HIJOS 2 

void lanzanieto(int i)
{
    int proceso;

    proceso = fork();
        if (proceso > 0) {
                wait(NULL);
        } else if (proceso == 0) {
            printf("Process Pid: %d PPid: %d (position: %d).\n",getpid(),getppid(), i);
        } else if (proceso == -1) {
            perror("fallo en fork");
            exit(EXIT_FAILURE);
        }
}
int main(void)
{
    int proceso, i;

    for (i=0; i<NUM_HIJOS; i++) {
        proceso = fork();

        if (proceso == 0) {

            switch(i) {
                case 0:
                    printf("Process Pid: %d PPid: %d (position: %d).\n",getpid(),getppid(), i);
                    lanzanieto(i);
                    exit(0);
                case 1:
                    printf("Process Pid: %d PPid: %d (position: %d).\n",getpid(),getppid(), i);
                    lanzanieto(i);
                    lanzanieto(i);
                    exit(0);        
            }

        }  else if (proceso == -1) {
            perror("fallo en fork");
            exit(EXIT_FAILURE);
        }

    }
    proceso = wait(NULL);
    while (proceso > 0) {
        proceso = wait(NULL);
    }
    /* ************************************* */
    if (proceso == -1 && errno != ECHILD) {
        perror("fallo en wait");
        exit(EXIT_FAILURE);
    }
}

Upvotes: 2

Views: 233

Answers (2)

Valentin Trinqu&#233;
Valentin Trinqu&#233;

Reputation: 1072

Concept

Firstly, create a fork() will look like this :

id = fork(); 
if (id < 0) {
    /* error */
    exit(1);
} 
else if (i > 0) { /* Parent > 0 */
    /* parent logic */
} 
else { /* Child = 0 */
    /* child logic */
}

fork() will create a child process along side the parent process.

Therefore, if you want to match your tree (and based on your existing code), the process diagram will look like :

parent : fork()
           |--> parent : fork()
           |               |--> parent
           |               |--> child_2
           |
           |--> child_1 : fork()
                           |--> child_1
                           |--> sub_child_1

To put it simply, you have to recursively fork() inside the parent and every new child process.

However acknowledge that forking process that way aren't nice looking.

It could be better to have a function, let's say create_child(), which fork only from the parent :

parent : create_fork()
               |--> parent : create_child()
               |        |
               |        |--> parent : create_child()
               |        |      |
               |        |      |--> parent 
               |        |      |--> child_3 : do_whatever()
               |        |
               |        |--> child_2 : do_whatever()
               |        
               |--> child_1 : do_whatever()

Solution

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

void print_pid(char *proc_name)
{
    printf("%s: %d\n", proc_name, getpid());
}

int create_child(void)
{
    pid_t child_pid = fork();
    if (child_pid == 0)
    {
        print_pid("child");
    }
    else if (child_pid < 0)
    {
        perror("create_child");
    }
    return (child_pid);
}

int make_babies(int babies_number)
{
    /* if no baby */
    if (babies_number <= 0)
        return 0;

    /* if baby(ies) */
    pid_t child_pid = create_child();
    if (child_pid > 0)
    {
        make_babies(babies_number - 1);
        waitpid(child_pid, NULL, 0);
    }
    return child_pid;
}

int main(void)
{
    print_pid("parent");
    make_babies(50);
    return errno;
}

Upvotes: 4

ymett
ymett

Reputation: 2454

You must remember that both the child process and the parent process continue executing the same code. When you call lanzanieto(i) twice in case 1: in main(), both the parent and the child from the first call to lanzanieto(i) (which are the child and grandchild of the original parent) continue on to the second call to lanzanieto(i), so both produce another child.

Upvotes: 1

Related Questions