Make children process wait until receiving parent's signal

21,387

Solution 1

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.

Solution 2

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

I think problem is, child Processes are terminated immediately after they created. so
Use pause() function to wait for the signal to arrive.

And if some child Processes won't respond as expected try this also.

for (j = 0; j < n_task; j++)
    {
            kill(pid_array[j], SIGUSR1); 
            sleep(1);
    }
Share:
21,387
Zk1001
Author by

Zk1001

Updated on November 11, 2020

Comments

  • Zk1001
    Zk1001 over 3 years

    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);                
        }
    
  • Jonathan Leffler
    Jonathan Leffler over 10 years
    The pause() function is the classic and simplest way to wait for a signal to arrive. It never returns normally; it only ever returns when a signal interrupts it.
  • Zk1001
    Zk1001 over 10 years
    this is somewhat similar the Duck's answer so I will comment here. I tried this but among 4 threads created, only 1 (sometimes) 2 threads are executed. Is there still something missing?
  • Deadlock
    Deadlock over 10 years
    for (j = 0; j < n_task; j++) { kill(pid_array[j], SIGUSR1); sleep(1); } try this way, it'll work. ( i don't know exactly why this happen but i think it's because parent process send signal, before some child Processes install the signal handler.)
  • Deadlock
    Deadlock over 10 years
    But this will not help you to achieve your purpose, to start (a function - to measure time) at the same time from all the children. But all child Processes will be executed.
  • Zk1001
    Zk1001 over 10 years
    Yes it works as you thought. Great. But then, I have to delay the signal sends! This is not what I wanted. I want the send the signal, to be more accurate, broatcast, to all children and let them start at the same time, more or less. Anyone could give a hint?
  • Duck
    Duck over 10 years
    Are you guys for real? Somewhat similar?
  • Zk1001
    Zk1001 over 10 years
    Tried your code. But it doesn't make all 4 tasks start at the same time. To be more specific, I added sleep(1) in measure_time(). The children print their "received signal" on a basis of 1 second. Could you give it one more try?
  • Duck
    Duck over 10 years
    I edited the parent kill/wait code into 2 loops. Maybe that is what you were seeing. My apologies for being short with you. Not even finished with my morning coffee.