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

标签 c linux process signals

我正在学习如何在 Linux 中使用信号。有 4 个子进程和 1 个父进程。我的输出应该在这些阶段进行:

parent 收到 child 1的信号

parent 收到 child 2的信号

父级接收到子级 3 的信号

parent 收到 child 4的信号

初始化结束

第一阶段开始

child 1 收到来自 parent 的信号

child 2 收到来自 parent 的信号

child 3 收到来自 parent 的信号

child 4 收到来自 parent 的信号

parent 收到 child 1的信号

parent 收到 child 2的信号

父级接收到子级 3 的信号

parent 收到 child 4的信号

第一阶段结束

第 2 阶段开始

child 1 收到来自 parent 的信号

child 2 收到来自 parent 的信号

child 3 收到来自 parent 的信号

child 4 收到来自 parent 的信号

我目前正在尝试在第 1 阶段结束之前完成该部分,但我很挣扎。这是我的代码:

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

我的输出是这样的:

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

感谢您的宝贵时间。

最佳答案

您想要使用信号的目的与它们的设计目的并非 100% 匹配。最重要的问题是信号充当硬件中断 Controller 。如果相同值的多个信号“同时”发生,它们在接收器中看起来将合并为一个信号。在下面的例子中,我们通过对每个 child 使用不同值的 sleep 来解决这个问题。

因此,当内核重新安排进程时,它只是检查自上次进程处于事件状态以来是否收到了每个信号,并在需要时将它们转发到进程中。它不知道发生了多少次。

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

图像内核对每个进程都有一个记录,说明它在休眠时收到了哪些信号。

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

信号用于“插入”其他进程。一个很好的例子是使进程重新加载配置文件。对于 IPC 通信,pipe() 是更好的方法。

关于c - 使用信号在父进程和多个子进程之间进行进程同步,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36532016/

相关文章:

c - fscanf 不扫描空格后的行

linux - 理解从进程内核栈中获取task_struct指针

c++ - CreateToolhelp32Snapshot 函数线程安全吗?

c# - 如何从接受输入的 C# 表单应用程序打开 cmd

c - 将 bool 字段添加到结构时出现语法错误( ‘:’ 标记之前应为 ‘,’ 、 ‘;’ 、 ‘}’ 、 ‘__attribute__’ 或 ‘=’ )

c - 具有广播信号的线程和互斥量

c - C 中的 strcasecmp 返回 156 而不是 0,有什么想法吗?

ruby - 同时创建多个子文件夹 Chef

Python:创建用户并向用户发送包含帐户详细信息的电子邮件

java - 如何一次销毁运行时中的所有进程?