Search code examples
clinuxpipeforkkill

How a child process kill other child process and then terminate?


Here is the code, where parent process writes a string input in pipe and children processes read this from pipe. If child process reads from pipe the word "end", then i want to terminate all the processes and then terminate itself, and if reads the word "finish" i want to raise a signal to father for killing all the processes and then exit. I run the code and i had segmentation fault. Why it is wrong?

#define _POSIX_SOURCE
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h>
void measure_time(int sig)
{
    printf("child [%d] received signal %d\n", getpid(), sig);
}
int main(int argc, char *argv[])
{
    int n_task = 4;
    pid_t pid;
    pid_t pid_array[n_task];
    int fd[2];
    for (int i = 0; i < n_task; i++)
    {
        pid = fork();
        if (pipe(fd) == -1)
        {
            perror(" pipe ");
            exit(1);
        }
        if (pid < 0)
        {
            perror("fork");
            exit(1);
        }
        if (pid == 0) //child
        {
            char *buf;
            close(fd[1]);
            read(fd[0], buf, 10);
            printf("I read: %s", buf);
            if (strcmp(buf, "end") == 0)
            {
                for (int i = 0; i < n_task; i++)
                    kill(pid_array[i], SIGUSR1);
            }else if(strcmp(buf,"finish") == 0){
                /*Here i want father to kill all children and then exit.*/
            }
            exit(0);
        }
        close(fd[0]);
        char *buf;
        printf("Give the input string: \n");
        scanf("%s", buf);
        write(fd[1], buf, strlen(buf));
        close(fd[1]);
        pid_array[i] = pid;
    }
    sleep(1);
    for (int i = 0; i < n_task; i++)
        wait(NULL);
    return (0);
}

Solution

  • Besides the issue of uninitialized buf identified by @G. Sliepen, the pipe() need be called before fork() as file descriptors are kept open when forking child process(s). This is also how pipe works.

    You can try to change your code snippet to put pipe() before fork().

    ...
            if (pipe(fd) == -1)
            {
                perror(" pipe ");
                exit(1);
            }
            pid = fork();
            if (pid < 0)
            {
                perror("fork");
                exit(1);
            }
    ...
    

    Please read the manual page of pipe(2) in which an example presented.

    SO has this post fork() and pipes() in c explained this as well.

    Update for terminating process(s)

    This child process has no knowledge about existence of its siblings, but its parent process has. If not explicitly required, you can let the parent to do so, i.e. to "end" all child processes.

    BTW, instead of sending signal SIGUSR1 it is better to send SIGTERM signal. Although SIGUSSR1 can cause the target process be terminated by default (see signal(7)).

    To "finish", i.e. to kill (or terminate) all the child processes as well as parent process, you can simplly kill the parent. All its descendants got killed as well. Or, you can send signal to the same process group. See kill(2).