【问题标题】:SIGALRM in C does not executing in the HandlerC 中的 SIGALRM 不在处理程序中执行
【发布时间】:2021-01-20 20:54:45
【问题描述】:

使用 SIGSTOP 停止子进程后,我想使用 SIGALRM 每 3 秒执行一次子进程, 但处理程序不起作用。这是我的代码:

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

void singAlrm(int sig)
{
    printf("HELLO from SIGALRM");
    kill(getpid(), SIGCONT);
}

int main()
{
    int Sense1 = 1;
    int Sense2 = 0;

    int pid1 = fork();
    signal(SIGALRM, singAlrm);
    if (pid1 == 0)// fils1
    {
        while (1)
        {
            kill(getpid(), SIGSTOP);
            if (Sense1 == 1)
            {
                printf("sense 1 working \n");
                Sense1 = 0;
            }
            else
            {
                printf(" sense 1 not working\n");
                Sense1 = 1;
            }
        }
        exit(0);
    }
    else// pere
    {
        int pid2 = fork();
        if (pid2 == 0)
        {
            while (1)
            {
                kill(getpid(), SIGSTOP);
                if (Sense2 == 1)
                {
                    printf("sense 2 is not working\n");
                    Sense2 = 0;
                }
                else
                {
                    printf("sense 2 is working\n");
                    feuCouleurSenseBA = 1;
                }
            }
            exit(0);
        }
        else
        {
            while (1)
            {
                sleep(3);

                signal(SIGALRM, singAlrm);
                kill(pid2, SIGALRM);
                kill(pid1, SIGALRM);// here I have a problem when I call SIGALRM
            }
        }
    }
}

我想得到结果

sense 1 is working
sense 2 is not working 
sense 1 is not working 
sense 2 is working
.
.

【问题讨论】:

  • 被 SIGSTOP 停止的进程在收到 SIGCONT 之前不会做任何事情。您可能想改用sigsuspendsigwaitinfo,或者更好的是,找到一种根本不使用信号的方法。
  • 是的,我知道,但我在处理程序中使用 SIGCONT,但我不知道为什么它不执行。
  • 推荐使用 sigaction() 而不是 signal()。来自 Ubuntu 20.04 上的“man signal”:“signal() 的唯一可移植用途是将信号的处置设置为 SIG_DFL 或 SIG_IGN。使用 signal() 建立信号处理程序时的语义因系统而异(以及 POSIX.1 显式允许这种变化);请勿将其用于此目的。”
  • @karim SIGALRM 处理程序不会运行,直到 已停止的进程收到某个未停止的进程发送的 SIGCONT。
  • 应该feuCouleurSenseBA = 1;真的是Sense2 = 1;吗?

标签: c linux bash multithreading signals


【解决方案1】:

您可能希望用SIGCONT(而不是SIGALRM)替换您从父进程发送给其子进程的信号:以SIGSTOP 停止的进程将无法处理任何类型的信号。

当我运行一个命令并发送一个SIGSTOP 给它(Ctrl + Z)时会发生这种情况:

$ sleep 360
^Z
[1]+  Stopped                 sleep 360
$ pkill -SIGINT sleep
# Does nothing

当程序恢复时,将处理信号:

$ pkill -SIGCONT sleep
[1]-  Interrupt               sleep 360

以下是修改后的代码的程序会发生什么:

$ ./a.out
sense 2 is working
sense 1 working
sense 2 is working
 sense 1 not working
sense 2 is working
sense 1 working

【讨论】:

    【解决方案2】:

    由于子进程通过SIGSTOP 停止,它们只会在通过发送SIGCONT 唤醒时执行任何操作,您应该使用

    kill(pid1, SIGCONT);
    kill(pid2, SIGCONT);
    

    在您向父进程发送警报信号之前,为SIGALRM 设置处理程序不会影响任何事情。您尚未使用 alarm() 设置警报,因此您不会收到警报信号。如果您使用sleep() 会发生什么并没有明确定义。由于父级没有等待SIGCONT,因此向自身发送信号的父级将无济于事,尤其是在未调用发送信号的处理程序时。

    请注意,您不应该从信号处理程序中调用printf() — 有关更多信息,请参阅How to avoid using printf() in a signal handler?。如果你调用printf(),你需要用换行符结束输出以确保它被打印——或者使用fflush()

    这是似乎可以工作的代码:

    #include "stderr.h"
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    #include <signal.h>
    #include <sys/wait.h>
    
    static void singAlrm(int sig)
    {
        printf("HELLO from SIGALRM %d\n", sig);
        //kill(getpid(), SIGCONT);
    }
    
    int main(int argc, char **argv)
    {
        if (argc > 0)
            err_setarg0(argv[0]);
        err_setlogopts(ERR_PID|ERR_MILLI);
        int Sense1 = 1;
        int Sense2 = 0;
    
        int pid1 = fork();
        signal(SIGALRM, singAlrm);
        if (pid1 == 0)// fils1
        {
            err_remark("Child 1 at work - Sense1 = %d\n", Sense1);
            while (1)
            {
                kill(getpid(), SIGSTOP);
                if (Sense1 == 1)
                {
                    printf("sense 1 working\n");
                    Sense1 = 0;
                }
                else
                {
                    printf("sense 1 not working\n");
                    Sense1 = 1;
                }
                err_remark("Child 1 - Sense1 now %d\n", Sense1);
            }
            exit(0);
        }
        else// pere
        {
            int pid2 = fork();
            if (pid2 == 0)
            {
                err_remark("Child 2 at work - Sense2 = %d\n", Sense2);
                while (1)
                {
                    kill(getpid(), SIGSTOP);
                    if (Sense2 == 1)
                    {
                        printf("sense 2 is not working\n");
                        Sense2 = 0;
                    }
                    else
                    {
                        printf("sense 2 is working\n");
                        Sense2 = 1;
                    }
                    err_remark("Child 2 - Sense2 now %d\n", Sense2);
                }
                exit(0);
            }
            else
            {
                while (1)
                {
                    err_remark("Parent about to sleep\n");
                    sleep(3);
                    err_remark("Parent woke up\n");
                    //signal(SIGALRM, singAlrm);
                    kill(pid2, SIGCONT);
                    kill(pid1, SIGCONT);
                }
            }
        }
    }
    

    我在 GitHub 上的 SOQ(堆栈溢出问题)存储库中使用了一些代码作为文件 stderr.cstderr.hsrc/libsoq 子目录中。这使我可以将 PID 和时间信息放入使用 err_remark() 打印的消息中。

    示例输出(源代码alarm47.c,程序alarm47):

    alarm47: 2020-10-05 20:31:44.593 - pid=28446: Parent about to sleep
    alarm47: 2020-10-05 20:31:44.593 - pid=28447: Child 1 at work - Sense1 = 1
    alarm47: 2020-10-05 20:31:44.593 - pid=28448: Child 2 at work - Sense2 = 0
    alarm47: 2020-10-05 20:31:47.597 - pid=28446: Parent woke up
    alarm47: 2020-10-05 20:31:47.598 - pid=28446: Parent about to sleep
    sense 2 is working
    alarm47: 2020-10-05 20:31:47.598 - pid=28448: Child 2 - Sense2 now 1
    sense 1 working
    alarm47: 2020-10-05 20:31:47.598 - pid=28447: Child 1 - Sense1 now 0
    alarm47: 2020-10-05 20:31:50.598 - pid=28446: Parent woke up
    sense 2 is not working
    alarm47: 2020-10-05 20:31:50.598 - pid=28446: Parent about to sleep
    alarm47: 2020-10-05 20:31:50.598 - pid=28448: Child 2 - Sense2 now 0
    sense 1 not working
    alarm47: 2020-10-05 20:31:50.598 - pid=28447: Child 1 - Sense1 now 1
    alarm47: 2020-10-05 20:31:53.601 - pid=28446: Parent woke up
    sense 2 is working
    sense 1 working
    alarm47: 2020-10-05 20:31:53.601 - pid=28448: Child 2 - Sense2 now 1
    alarm47: 2020-10-05 20:31:53.601 - pid=28446: Parent about to sleep
    alarm47: 2020-10-05 20:31:53.601 - pid=28447: Child 1 - Sense1 now 0
    alarm47: 2020-10-05 20:31:56.604 - pid=28446: Parent woke up
    sense 2 is not working
    alarm47: 2020-10-05 20:31:56.604 - pid=28448: Child 2 - Sense2 now 0
    sense 1 not working
    alarm47: 2020-10-05 20:31:56.605 - pid=28446: Parent about to sleep
    alarm47: 2020-10-05 20:31:56.605 - pid=28447: Child 1 - Sense1 now 1
    alarm47: 2020-10-05 20:31:59.606 - pid=28446: Parent woke up
    alarm47: 2020-10-05 20:31:59.606 - pid=28446: Parent about to sleep
    sense 2 is working
    sense 1 working
    alarm47: 2020-10-05 20:31:59.606 - pid=28448: Child 2 - Sense2 now 1
    alarm47: 2020-10-05 20:31:59.606 - pid=28447: Child 1 - Sense1 now 0
    

    提供或获取调试信息,这几乎就是您所追求的。请注意,两个子进程响应的顺序并不能保证。

    请注意,警报处理程序永远不会被调用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-01-21
      • 2015-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多