cs276
cs276

Reputation: 21

Creating a sequential child - child process in c

I wish to create a sequential process that will create a specified number of children. For example if parent process ID is 769 the process will be as follows:

769(parent) -> 770(first child) -> 771(grand child) ... -> xx (n*grand child)

based on the number of children I want. PID of the children doesn't matter as long as they are sequential and have no siblings.

int main(int argc, char **argv) {
    int i;
    int iterations;

    if (argc != 2) {
        fprintf(stderr, "Usage: forkloop <iterations>\n");
        exit(1);
    }

    iterations = strtol(argv[1], NULL, 10);

    int n = fork();
    for (i = 0; i < iterations; i++) {
        if(n == 0) {
            printf("ppid = %d, pid = %d, i = %d\n", getppid(), getpid(), i);
            n = fork();
        }
        if (n < 0) {
            perror("fork");
            exit(1);
        }
       //printf("ppid = %d, pid = %d, i = %d\n", getppid(), getpid(), i);
    }
    // printf("ppid = %d, pid = %d\n", getppid(), getpid());
    return 0;
}

I have made this but I believe this is a bit wrong. Could anyone help out?

Upvotes: 0

Views: 1053

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 753515

Think through the logic carefully. You're close, but need to get closer. This works:

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

int main(int argc, char **argv)
{
    if (argc != 2)
    {
        fprintf(stderr, "Usage: forkloop <iterations>\n");
        exit(1);
    }

    int iterations = strtol(argv[1], NULL, 10);
    if (iterations < 1 || iterations > 20)
    {
        fprintf(stderr, "invalid iterations %d (1..20 allowed)\n", iterations);
        exit(1);
    }
    printf("Initial process: PID %d (parent %d)\n", (int)getpid(), (int)getppid());
    fflush(stdout);
    int i;
    for (i = 0; i < iterations; i++)
    {
        int pid = fork();
        if (pid < 0)
        {
            perror("fork");
            exit(1);
        }
        else if (pid == 0)
        {
            /* Child - report ID */
            printf("ppid = %d, pid = %d, i = %d\n", getppid(), getpid(), i);
            fflush(stdout);
        }
        if (pid != 0)
        {
            /* Parent - break loop and wait for kid (and grandkid, and ...) to die */
            break;
        }
    }

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

    return i;
}

(There's no guarantee that pid_t returned by getpid() et al is actually an int, though it is normally equivalent. I added the casts to ensure there is no problem, though in practice you can get away without them. The last fflush() is not strictly needed; the process exits which flushes the output anyway. The earlier ones are a good idea; you could get confusing output if they were absent and the output of the program was piped to some process to capture it. Before you fork(), it's a good idea to have no pending output — so fflush(0) aka fflush(NULL) is perhaps a good idea, in general, though here it isn't necessary.)

Sample outputs (source code kids17.c, program name kids17):

$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes \
>     -Wstrict-prototypes kids17.c -o kids17 
$ kids17
Usage: forkloop <iterations>
$ kids17 4
Initial process: PID 2686 (parent 888)
ppid = 2686, pid = 2687, i = 0
ppid = 2687, pid = 2688, i = 1
ppid = 2688, pid = 2689, i = 2
ppid = 2689, pid = 2690, i = 3
PID 2689: child 2690 exited with status 0x0400
PID 2688: child 2689 exited with status 0x0300
PID 2687: child 2688 exited with status 0x0200
PID 2686: child 2687 exited with status 0x0100
$ …some work done…
$ kids17 10
Initial process: PID 2704 (parent 888)
ppid = 2704, pid = 2705, i = 0
ppid = 2705, pid = 2706, i = 1
ppid = 2706, pid = 2707, i = 2
ppid = 2707, pid = 2708, i = 3
ppid = 2708, pid = 2709, i = 4
ppid = 2709, pid = 2710, i = 5
ppid = 2710, pid = 2711, i = 6
ppid = 2711, pid = 2712, i = 7
ppid = 2712, pid = 2713, i = 8
ppid = 2713, pid = 2714, i = 9
PID 2713: child 2714 exited with status 0x0A00
PID 2712: child 2713 exited with status 0x0900
PID 2711: child 2712 exited with status 0x0800
PID 2710: child 2711 exited with status 0x0700
PID 2709: child 2710 exited with status 0x0600
PID 2708: child 2709 exited with status 0x0500
PID 2707: child 2708 exited with status 0x0400
PID 2706: child 2707 exited with status 0x0300
PID 2705: child 2706 exited with status 0x0200
PID 2704: child 2705 exited with status 0x0100
$

I didn't have any other processes actively spawning child processes while I was running this testing.

Upvotes: 1

Related Questions