简体   繁体   English

使用信号在父进程和多个子进程之间进行进程同步

[英]process synchronization between a parent and multiple child processes using signals

I am learning how to use signals in linux. 我正在学习如何在Linux中使用信号。 There are 4 child processes and one parent process. 有4个子进程和1个父进程。 My output is supposed to go in these stages: 我的输出应该进入以下阶段:

Parent receives signal from child 1 父母收到孩子1的信号

Parent receives signal from child 2 家长收到孩子2的信号

Parent receives signal from child 3 家长收到孩子3的信号

Parent receives signal from child 4 父母收到孩子4的信号

Init ended 初始化结束

Phase 1 begins 第一阶段开始

Child 1 receives signal from parent 孩子1从父母那里收到信号

Child 2 receives signal from parent 子级2接收来自父级的信号

Child 3 receives signal from parent 孩子3从父母那里收到信号

Child 4 receives signal from parent 孩子4从父母那里收到信号

Parent receives signal from child 1 父母收到孩子1的信号

Parent receives signal from child 2 家长收到孩子2的信号

Parent receives signal from child 3 家长收到孩子3的信号

Parent receives signal from child 4 父母收到孩子4的信号

Phase 1 ends 第一阶段结束

Phase 2 begins 第二阶段开始

Child 1 receives signal from parent 孩子1从父母那里收到信号

Child 2 receives signal from parent 子级2接收来自父级的信号

Child 3 receives signal from parent 孩子3从父母那里收到信号

Child 4 receives signal from parent 孩子4从父母那里收到信号

I am currently trying to do the part before Phase 1 ends and I am struggling. 我目前正在尝试在第1阶段结束之前做这部分工作,而且我正在挣扎。 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. 您想要使用的信号与它们的设计并非100%匹配。 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. 对于IPC通信,pipe()是更好的方法。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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