等待多个进程的信号时sigwait有什么问题

时间:2019-04-22 17:11:02

标签: c linux signals fork

在这种情况下,我有多个进程,其中1个父进程2个孩子进程。我希望每个孩子都从其信号处理程序返回后继续前进。但是有时它们会卡住,有时只有其中一种会继续。我怎么了实际上,我正在尝试执行类似于唤醒信号的操作。我可以发出更多信号,但是如果需要100个孩子怎么办?因此,我只想通过使用SIGUSR2

来实现
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>


void tellerHandler(int sig) {
    //write(STDERR_FILENO, "Teller has caught SIGUSR2 signal\n", 33);
    printf("pid %u Teller has caught SIGUSR2 signal\n", getpid());
}

int main() {

    int NUM_OF_CHILDREN = 2;
    struct sigaction sa;
    memset(&sa, 0, sizeof(sa));
    sa.sa_flags = 0;
    sa.sa_handler = tellerHandler;
    if (sigaction(SIGUSR2, &sa, NULL) == -1) {
        perror("sigaction error");
        exit(-1);
    }

    sigset_t new_mask;
    sigfillset(&new_mask);
    sigdelset(&new_mask, SIGUSR2);

    int returnedPid = -1;
    pid_t pidList[NUM_OF_CHILDREN];

    for (int i = 1; i < 1 + NUM_OF_CHILDREN; ++i) {
        if ((returnedPid = fork()) == 0) {
            break;
        } else {
            pidList[i - 1] = returnedPid;
        }
    }

    if (returnedPid == 0) {
        sigsuspend(&new_mask);
        printf("child %u returned from handler\n", getpid());
    } else {
        for (int i = 0; i < NUM_OF_CHILDREN; ++i) {
            printf("child %u\n", pidList[i]);
            kill(pidList[i], SIGUSR2);
        }

        for (int i = 0; i < NUM_OF_CHILDREN; ++i) {
            waitpid(pidList[i], 0, 0);
        }
        puts("parent exiting...\n");
    }

    puts("donee");
}

一些运行多次的不同输出,

child 66313
child 66314
pid 66313 Teller has caught SIGUSR2 signal
child 66313 returned from handler
pid 66314 Teller has caught SIGUSR2 signal

---

child 66330
child 66331
pid 66330 Teller has caught SIGUSR2 signal
pid 66331 Teller has caught SIGUSR2 signal

---

当我将孩子人数增加到3时,以下输出就像

child 66738
child 66739
child 66740
pid 66739 Teller has caught SIGUSR2 signal
pid 66738 Teller has caught SIGUSR2 signal
child 66738 returned from handler
donee
pid 66740 Teller has caught SIGUSR2 signal

1 个答案:

答案 0 :(得分:0)

您的基本问题是,父母发送SIGUSR2信号与孩子呼叫sigsuspend之间存在竞争状态。如果孩子的起步较慢并且父母先运行,则它可能在孩子调用sigsuspend之前发送信号。由于孩子在信号处理程序处于活动状态且未屏蔽的情况下启动(从fork()返回),因此它可能会立即捕获信号(并打印有关捕获信号的消息),然后返回并调用sigsuspend。由于此时信号已被处理,因此sigsuspend将等待第二个永远不会出现的信号。

解决方法是确保SIGUSR2在子级中被阻止,直到调用sigsuspend。在调用fork的循环之前放入代码以完成此操作:

sigset_t ss;
sigemptyset(&ss);
sigaddset(&ss, SIGUSR2);
sigprocmask(SIG_BLOCK, &ss, 0);