简体   繁体   中英

process synchronization between a parent and multiple child processes using signals

I am learning how to use signals in linux. There are 4 child processes and one parent process. My output is supposed to go in these stages:

Parent receives signal from child 1

Parent receives signal from child 2

Parent receives signal from child 3

Parent receives signal from child 4

Init ended

Phase 1 begins

Child 1 receives signal from parent

Child 2 receives signal from parent

Child 3 receives signal from parent

Child 4 receives signal from parent

Parent receives signal from child 1

Parent receives signal from child 2

Parent receives signal from child 3

Parent receives signal from child 4

Phase 1 ends

Phase 2 begins

Child 1 receives signal from parent

Child 2 receives signal from parent

Child 3 receives signal from parent

Child 4 receives signal from parent

I am currently trying to do the part before Phase 1 ends and I am struggling. Here is my code:

#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#define MAXCP 3
int ccount=0;
void p_action(int sig){
   if (sig == SIGUSR2){
      printf("\ncontroller(%d): Received signal SIGUSR2 from child   process\n", 
            (int)getpid());
    }
    --ccount;
 }

 void c_action(int sig){
    if (sig == SIGUSR1){
      printf("\ncompute(%d): Received signal SIGUSR1 from parent process %d\n", 
            (int)getpid(), (int)getppid());
    }
    exit(0);
 }

int main(){

pid_t pid[MAXCP], parent_pid;
//int nprocs = 0;
ccount = MAXCP;

static struct sigaction pact, cact[MAXCP];

pact.sa_handler = p_action;
sigaction(SIGUSR2, &pact, NULL);


int count;
for (count = 0; count < MAXCP; count++){
    switch(pid[count] = fork()){
        case -1:
            perror("Fork error");
            exit(1);
        case 0:
            //sleep(1);
            cact[count].sa_handler = c_action;
            sigaction(SIGUSR1, &cact[count], NULL);
            printf("Sending SIGUSR2 to parent");
            kill(getppid(), SIGUSR2);
            pause();
            break;
        default:
            pause();
            //printf("Parent is sleeping");

            while (ccount != MAXCP){
                sleep(60);
            }
            for (ccount = 0; ccount < MAXCP; ccount++)
                kill(pid[count], SIGUSR1);
            break;

    }   
}


return 0;
}

My output is such:

// When I use the above code
controller(3132): Received signal SIGUSR2 from child process
// When I comment out the pause in the child section
controller(3140): Received signal SIGUSR2 from child process
Sending SIGUSR2 to parent
controller(3141): Received signal SIGUSR2 from child process
Sending SIGUSR2 to parentSending SIGUSR2 to parentSending SIGUSR2 to     parentSending SIGUSR2 to parentSending SIGUSR2 to parent
controller(3142): Received signal SIGUSR2 from child process
^C

Thanks for your time.

What you want to use signals for, is not 100% match with what they are designed for. The most significant problem is that signals acts as an hardware interrupt controller. If multiple signals of the same value happens "at the same time", they will appear to be merged into just one signal in the receiver. In the example below, we work around this by using sleep with different value in each child.

So when the kernel is the reschedule the process, it just checks if each signal has been received since last time process was active, and forwards them into the process if needed. It does not know how many times it happened.

#include <unistd.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#define MAXCP 3
volatile int ccount=0;
void p_action(int sig, siginfo_t *info, void *ptr){
   if (sig == SIGUSR2){
      printf("\ncontroller(%d): Received signal SIGUSR2 from child %d process\n",
            (int)getpid(), (int)info->si_pid);
    }
    --ccount;
 }

 void c_action(int sig){
    if (sig == SIGUSR1){
      printf("\ncompute(%d): Received signal SIGUSR1 from parent process %d\n",
            (int)getpid(), (int)getppid());
    }
 }

int main(){
    int count;
    pid_t pid[MAXCP];
    ccount = MAXCP;

    struct sigaction pact;

    pact.sa_flags = SA_SIGINFO | SA_RESTART; /* if signal comes on top of each other, we need this */
    pact.sa_sigaction = p_action;
    sigaction(SIGUSR2, &pact, NULL);

    /* spawdn children */
    for (count = 0; count < MAXCP; count++){
        switch(pid[count] = fork()){
            case -1:
                perror("Fork error");
                exit(1);
            case 0:
                {
                    struct sigaction cact;
                    cact.sa_flags = 0;
                    cact.sa_handler = c_action;
                    sigaction(SIGUSR1, &cact, NULL);
                    pause();
                    sleep(1);
                    printf("Sending SIGUSR2 to parent (%d)\n", getppid());
                    sleep(count+1);
                    kill(getppid(), SIGUSR2);
                    exit(0);
                    break;
                }
            default:
                break;
        }
    }

    sleep (1); /* let children have time to configure sigaction() */

    /* notify all children */
    for (count = 0; count < MAXCP; count++){
        printf ("Sending SIGUSR1 to child %d\n", (int)pid[count]);
        kill(pid[count], SIGUSR1);
    }

    /* wait for children to notify back */
    while (ccount)
    {
         usleep(10000); /* else CPU throttles */
    }

    for (count = 0; count < MAXCP; count++){
        int status;
        waitpid (pid[count], &status, 0);
        printf ("Child process %d reaped. status=%d\n", pid[count], status);
        kill(pid[count], SIGUSR1);
    }

    return 0;
}

Image the kernel has a record per process about which signals it has received while sleeping.

struct Process
{
   bool hasReceivedSIGINT;
   bool hasReceivedSIGUSR1;
   bool hasReceivedSIGUSR2;
   bool hasReceivedSIGUSR3;
};

A signal is used to "nudge" other processes. A good example is to make a process reload configuration file. For IPC communication, pipe() is a better approach.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM