Chad D
Chad D

Reputation: 319

Using switch statements to fork two processes

I'm taking an intro to C course and I've become a bit stumped on the first assignment. We've been tasked with creating a parent processes and two child processes. All of the examples the text has shown us so far involve switch statements with one parent and one child. I'm a bit confused about how to translate this into one parent and two child processes. Here is what I have so far:

#include <stdio.h>

int main() {
    int i, pid, status;
    pid = fork();
    switch(pid) {
    case -1:
        /* An error has occurred */
        printf("Fork Error");
        break;
    case 0:
        /* This code is executed by the first parent */
        printf("First child process is born, my pid is %d\n", getpid());
        printf("First child parent process is %d\n", getppid());
        for (i=1; i<=10; i++)
            printf("First child process, iteration: %d\n", i);
        printf("First child dies quietly.\n");
        break;
    default:
        /* This code is executed by the parent process */
        printf("Parent process is born, my pid is %d\n", getpid());
        wait(&status);
        printf("Parent process dies quietly.\n");
    }
}

This works perfect for this one process:

Parent process is born, my pid is 10850
First child process is born, my pid is 10851
First child parent process is 10850
First child process, iteration: 1
First child process, iteration: 2
First child process, iteration: 3
First child process, iteration: 4
First child process, iteration: 5
First child process, iteration: 6
First child process, iteration: 7
First child process, iteration: 8
First child process, iteration: 9
First child process, iteration: 10
First child dies quietly.
Parent process dies quietly.

Essentially I just need to do the same thing with a second process... something like:

printf("Second child process is born, my pid is %d\n", getpid());
printf("Second child parent process is %d\n", getppid());
for (k=1; k<=10; k++)
    printf("Second child process, iteration: %d\n", i);
printf("Second child dies quietly.\n");
break;

But I'm just not sure how to get there from what I have so far. Am I approaching this correct way? Is there a better method I should be using? Thanks so much.

Upvotes: 0

Views: 6551

Answers (3)

There is a general rule. When you use fork(2) you should always handle the three cases below:

  1. fork gave 0, you are in the child process
  2. fork gave a positive pid_t, you are in the parent process
  3. fork failed and gave -1

People (newbies) sometimes tend to forget the last (failure) case. But it does happen, and you might easily test that case by using setrlimit(2) with RLIMIT_NPROC in your grand-parent process to lower the limit on processes, often that grand-parent process is your shell (e.g. using ulimit Bash builtin with -u).

Now, how to handle the three cases is a matter of coding style. You can use switch but you can use two if. Your code uses a switch and is right to do so.

As a general rule, most system calls (listed in syscalls(2)) can fail, and you almost always need to handle the failure case (see errno(3) and use perror(3)).

Read also Advanced Linux Programming (freely downloadable).

I'm a bit confused about how to translate this into one parent and two child processes.

The fork system call is creating (on success) exactly one child process. So if you need two children, you should call it twice (and test failure on both calls) in a row. If you need one child and one grand child, you should do the second fork only when the first one gave 0. Of course you need to keep both (successful and positive) pid_t -e.g. in two variables- returned by your two calls to fork.

To avoid zombie processes, every successful fork should later have its wait system call (e.g. waitpid(2) or wait or wait4(2) or wait3). Where you do that wait depends if you want to have both children running at the same time or not. But every successful fork should have a corresponding successful wait call.

Read also signal(7) (and signal-safety(7)) about SIGCHLD if you want to be asynchronously notified about child processes change - notably termination. A common way is to install a SIGCHLD signal handler (e.g. using sigaction(2) or the old signal(2)) which just sets some global volatile sigatomic_t flag and test then clear that flag in convenient place in your code (e.g. in some event loop using poll(2)).

NB: notice that fork is not about C programming (fork is not defined in the C11 standard n1570 or its predecessor C99). It is a POSIX and Linux thing. Windows or z/OS or an Arduino microcontroller don't have it natively, but are programmable in some standard C.

Upvotes: 3

Pras
Pras

Reputation: 4044

You can put fork and switch case in loop so that it forks multiple processes, something like below:

Edit: You can remove if condition to call wait after each fork, alternately if you want to launch all children then wait for them to terminate, in each iteration you can collect pid of each child (in parent process ie in default switch case) in an array and in last iteration call waitpid in a loop(for each pid) to ensure each child process has exited

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
    int i, pid, status;
    int j = 0;
    int numChildren = 2;/*Change it to fork any number of children*/
    for(j = 0;j< numChildren;j++)
    {
            pid = fork();
            switch(pid) {
            case -1:
                /* An error has occurred */
                printf("Fork Error");
                break;
            case 0:
                /* This code is executed by the first parent */
                printf("First child process is born, my pid is %d\n", getpid());
                printf("First child parent process is %d\n", getppid());
                for (i=1; i<=10; i++)
                    printf("First child process, iteration: %d\n", i);
                printf("First child dies quietly.\n");
                exit(0);/*Otherwise it will fork its own child*/
                break;
            default:
                /* This code is executed by the parent process */
                printf("Parent process is born, my pid is %d\n", getpid());
                if(j == (numChildren - 1))/*You can remove this condition to wait after each fork*/
                {
                wait(&status);
                printf("Parent process dies quietly.\n");
                }
            }
        }
}

Upvotes: 2

nuji
nuji

Reputation: 11

To make 2 child you call fork()2x. So call fork with 2 different variable and then wait for them both.

Upvotes: -1

Related Questions