0

I am trying to use signal to sync N processes then print out something. Each child process register a handler which print "yo" and "hihi" when catching SIGUSR1. I use kill(0, SIGUSR1) to trigger every process. Since the default action for catching SIGUSR1 is being killed, I set a do-nothing handler for the main process so that it will wait all child died.

The fork and send signal program will repeat for k times, I expect it will show out N*k times "yo" and "hihi". However, it doesn't show enough "yo" and "hihi" as I expect. The number of "yo" is different every execution.

Here is my code, and thanks for your help!

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    #include <sys/wait.h>
    #include <time.h>
    #include <signal.h>
    #include <sys/time.h>
    #include <string.h>
    #define N 3 
    int pid_id[N];

    void handler2 (int signum)
    {
        printf("hihi\n");
    }

    void handler (int signum)
    {
        signal(SIGUSR2, handler2); 
        printf("yo\n");
        raise(SIGUSR2);
    }

    void handler_do_nothing (int signum)
    {
        ;
    }

    void child(int process_index)
    {
        struct sigaction sa;

        /* Register */
        memset(&sa, 0, sizeof(sa));
        sa.sa_handler = handler;
        sigaction(SIGUSR1, &sa, NULL);

        printf("I am %d.\n", getpid());
        pid_id[process_index] = getpid();
        sleep(1);

        exit(0);
    }

    int main()
    {
        int i, k, status;
        pid_t pid[N];
        pid_t pid_wait;

        struct sigaction sa_main;

        /* Register */    /* Main process will terminate if catch SIGUSR1 by default setting*/ 
        memset(&sa_main, 0, sizeof(sa_main));
        sa_main.sa_handler = handler_do_nothing;
        sigaction(SIGUSR1, &sa_main, NULL);

        /* Race k times */
        for (k=0;k<3;k++) 
        {

            for (i=0;i<N;i++)
            {
                pid[i] = fork();
                if (pid[i]==0)
                {
                    child(i);
                }
            }

             // sleep();
             kill(0, SIGUSR1);

            for (i=0;i<N;i++)
            {
                do
                {
                    pid_wait = waitpid(pid[i], &status, WNOHANG);
                    printf("I am waiting..\n");
                    sleep(1);
                }while(pid_wait != pid[i]);
            }
        }
        printf("all done\n");

        return 0;
    }
KennyYang
  • 235
  • 2
  • 13
  • 4
    For a start printf is not async safe, so you can't use it in a signal handler... See: http://stackoverflow.com/questions/16891019/how-to-avoid-using-printf-in-a-signal-handler – Joe Dec 16 '15 at 12:03

1 Answers1

1

Your child processes are being signalled before they have had time (i.e. execution resource scheduled) to install the new signal handler.

This means that when the main program sends SIGUSR1, some subset of the child processes will still have handler_do_nothing installed.

If you want to wait until the child processes have all finished setting up, you will need to add some interprocess communication mechanism - e.g. the children could signal the parent process when they are ready.

ecatmur
  • 152,476
  • 27
  • 293
  • 366
  • I don't understand why the child process will do handler_do_nothing..? In child process, I have registered handler..? – KennyYang Dec 16 '15 at 12:26
  • 1
    @KennyYang the main process runs in parallel with the child process, so it can get to `kill` before the child process gets to `sigaction`. – ecatmur Dec 16 '15 at 12:28