如何在 C++ 中使用信号以及它们如何反应?

How to use signals in C++ and How they react?

我正在尝试了解有关信号的所有交互,但我发现其中有一个我无法理解的有趣交互。

这是程序的摘要,我指示用 grandchild 执行 execvp,而 child 需要等待 grandchild 完成。它 运行 在没有任何信号交互的情况下是正确的。

void say_Hi(int num) { printf("Finished\n"); }

int main() {
    int i = 2;

    char *command1[] = {"sleep", "5", NULL};
    char *command2[] = {"sleep", "10", NULL};

    signal(SIGCHLD, SIG_IGN);
    signal(SIGUSR1, say_Hi);

    while(i > 0) {
        pid_t pid = fork();
        if (pid == 0) {
            pid_t pidChild = fork();
            if (pidChild == 0) {
                if (i == 2) {
                    execvp(command1[0], command1);
                } else {
                    execvp(command2[0], command2);
                }
            } else if (pidChild > 0) {
                waitpid(pidChild, 0, 0);
                // kill(pid, SIGUSR1);
                printf("pid finished: %d\n", pidChild);
                exit(EXIT_FAILURE);
            }
            exit(EXIT_FAILURE);
        } else {
            //parent immediately goes to next loop
            i--;
        }
    }
    cin >> i; //just for me to pause and observate answers above
    return 0;
}

如上图, kill(pid, SIGUSR1);被注释,程序运行正确

输出:

pid finished: 638532 //after 5 sec
pid finished: 638533 //after 10 sec

然而,当它被取消注释时。输出变为:

Finished
pid finished: 638610 //after 5 sec
Finished
Finished
Finished
Finished
pid finished: 638611 //after 5 sec too, why?
Finished

我想问:


如果我的代码看起来愚蠢或笨重,请原谅我,我是编程新手。感谢对我的代码和帮助的任何评论!

void say_Hi(int num) { printf("Finished\n"); }

printf 不能在信号处理程序中调用。 None 的 C 或 C++ 库函数(除了少数例外)可以在信号处理程序中调用。您甚至不能从信号处理程序中分配或删除任何内存(使用 C 或 C++ 库),除非使用 low-level OS 调用,如 brk()sbrk().这是因为一个非常简单的原因:none 的 C 或 C++ 库函数是 signal-safe(很少 例外)。只能从信号处理程序调用函数调用 that are explicitly designated 作为“signal-safe”。 None 的 C 或 C++ 库函数或 类(除了少数例外)是 signal-safe。结束。

唯一可以从信号处理程序调用的是 low-level 操作系统调用,如 read()write(),它们直接在文件句柄上运行。根据定义,它们是 signal-safe.

由于这个简单的原因,显示的代码在涉及信号时是未定义的行为。试图从这方面分析或弄清楚您的程序行为,例如为什么或为什么不看到此消息,是完全没有意义的。无法从逻辑上分析。这是未定义的行为。

答案:

kill(getpid(), SIG_USR1);