Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Make children process wait until receiving parent's signal

I want to create N children from a parent. I want all the children to start (a function - to measure time) at the same time. So I put the function in a signal handler and when the parent finish creating (fork) all children, it sends the signal (using kill(children_id)) to all children to let make start. The code is below but it doesn't work as expected. Specifically, it forked all children but does not execute function "measure_time" at all. This function does not thing but record execution time and print out. Could someone let me know if I am doing something wrong?

    int n_task = 4;
    for (i = 0; i < n_task; i++){
            pid = fork();
            if (pid < 0){
                    printf("cannot fork!\n");
            } else
            if (pid == 0){ //child
                    printf("printed from child [%d]\n", getpid());                        
                    signal(SIGUSR1, measure_time); //measure_time is a function
                    exit(0);
            } else {
                    pid_array[i] = pid;
            }
    }

    //This code is executed from parent only
    for (int i = 0; i < n_task; i++)
    {
            kill(pid_array[i], SIGUSR1);                
    }
like image 722
Zk1001 Avatar asked Feb 14 '23 17:02

Zk1001


1 Answers

if (pid == 0){ //child
    printf("printed from child [%d]\n", getpid());                        
    signal(SIGUSR1, measure_time); //measure_time is a function
    exit(0);
}

The children get created, set up the handler, and immediately exit (i.e. die). Make them sleep or block on something so there is actually time for the parent to deliver the signals.

Update

#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>   

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];

    for (int i = 0; i < n_task; i++)
    {
        pid = fork();

        if (pid < 0)
        {
            perror("fork");
            exit(1);
        }

        if (pid == 0) //child
        {
            printf("printed from child [%d]\n", getpid());
            signal(SIGUSR1, measure_time); //measure_time is a function
            sleep(5);

            exit(0);
        }

        //parent
         pid_array[i] = pid;
    }    

    //This code is executed from parent only
    sleep(1);

    for (int i = 0; i < n_task; i++)
        kill(pid_array[i], SIGUSR1);

    for (int i = 0; i < n_task; i++)
        wait(NULL);    

    return (0);
}

All processes and threads are subject to whims of the OS scheduler. In your initial code the children and the parent can potentially terminate before the sequence of events you hope to take place can ever occurs. The children can die before the parent ever sends a signal; the parent can send its signals before the children ever set up their handler (and SIGUSR1 kill the process because that is its default in the absence of a handler). There is so little code to execute all this takes place in milliseconds, less than the time than any of these processes gets scheduled to run (and thus setting up enough to fulfill your expections). I have added some sleep to give it all some breathing room and a wait so the parent doesn't die. This should allow you to see how it works.

like image 66
Duck Avatar answered Feb 27 '23 09:02

Duck