【问题标题】:Trouble sending and handling signals with children processes in C在 C 中使用子进程发送和处理信号时遇到问题
【发布时间】:2014-09-06 19:09:59
【问题描述】:

父进程fork出两个子进程,每个子进程分别替换SIGUSR1SIGUSR2信号。

父进程替换SIGINT信号,在捕获它时,分别向其子进程发送SIGUSR1SIGUSR2

按下 Ctrl-C 时的预期输出应该是:

Ctrl+C is pressed。
received SIGUSR1 signal
received SIGUSR2 signal

但是在 Ctrl-C 上我有

Ctrl+C is pressed。

我不知道为什么 sig_handler_1sig_handler_2 没有被执行。

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h>
void fun_ctrl_c(int);
void sig_handler_1(int);
void sig_handler_2(int);
pid_t pid1;
pid_t pid2;
int status;

int main() {
    pid1 = fork();
    if (pid1 == 0) {    // child 1
        // avoid to be killed
        (void) signal(SIGINT, SIG_IGN);
        // replace SIGUSR1
        (void) signal(SIGUSR1, sig_handler_1);
        raise(SIGSTOP);
    } else {
        pid2 = fork();
        if (pid2 == 0) {    // child 2
            // avoid to be killed
            (void) signal(SIGINT, SIG_IGN);
            // replace SIGUSR2
            (void) signal(SIGUSR2, sig_handler_2);
            raise(SIGSTOP);
        } else {    // parent
            (void) signal(SIGINT, fun_ctrl_c);
            waitpid(-1, &status, 0);
        }
    }
    return 0;
}

void fun_ctrl_c(int)
{
    printf("Ctrl+C is pressed。\n");
    kill(pid1 ,SIGUSR1);
    kill(pid2 ,SIGUSR2);
    (void) signal(SIGINT, SIG_DFL);
}

void sig_handler_1(int)
{
    printf("received SIGUSR1 signal\n");
}

void sig_handler_2(int)
{
    printf("received SIGUSR2 signal\n");
}

【问题讨论】:

  • 使用“替换”不是常用的术语。您似乎在“处理”信号,或“用不同的信号处理程序替换当前的信号处理程序”。

标签: c linux signals fork kill


【解决方案1】:

您的问题是您在子进程中执行raise(SIGSTOP);,因此它们被停止并且根本无法响应信号。

将其替换为 pause(); — 这样代码就可以工作了。

#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

void fun_ctrl_c(int);
void sig_handler_1(int);
void sig_handler_2(int);

pid_t pid1;
pid_t pid2;

int main(void)
{
    pid1 = fork();
    if (pid1 == 0)
    {
        (void) signal(SIGINT, SIG_IGN);
        (void) signal(SIGUSR1, sig_handler_1);
        pause();
        printf("PID %d exiting\n", (int)getpid());
    }
    else if ((pid2 = fork()) == 0)
        {
            (void) signal(SIGINT, SIG_IGN);
            (void) signal(SIGUSR2, sig_handler_2);
            pause();
            printf("PID %d exiting\n", (int)getpid());
        }
        else
        {
            (void) signal(SIGINT, fun_ctrl_c);
            int status;
            int pid;
            printf("Interrupt me!\n");
            while ((pid = waitpid(-1, &status, 0)) != -1)
                printf("Child %d exited with status 0x%.4X\n", pid, status);
            printf("Parent %d exiting\n", (int)getpid());
        }
    return 0;
}

void fun_ctrl_c(int signum)
{
    printf("Ctrl+C is pressed。Received SIGINT (%d) signal\n", signum);
    kill(pid1, SIGUSR1);
    kill(pid2, SIGUSR2);
    (void) signal(SIGINT, SIG_DFL);
}

void sig_handler_1(int signum)
{
    printf("received SIGUSR1 (%d) signal\n", signum);
}

void sig_handler_2(int signum)
{
    printf("received SIGUSR2 (%d) signal\n", signum);
}

示例运行(我调用了程序sigintusr12):

$ ./sigintusr12
Interrupt me!
^CCtrl+C is pressed。Received SIGINT (2) signal
received SIGUSR2 (31) signal
received SIGUSR1 (30) signal
PID 31184 exiting
PID 31183 exiting
Child 31184 exited with status 0x0000
Child 31183 exited with status 0x0000
Parent 31182 exiting
$

请注意,严格来说,您不应该在信号处理程序中使用printf()(以及许多其他函数,尤其是那些可能需要分配内存的函数)。它在这里可以正常工作,但这不是一个好习惯。请参阅How to avoid using printf() in a signal handler? 了解更多信息。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-06-20
    • 2020-03-06
    • 1970-01-01
    • 1970-01-01
    • 2023-03-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多