【问题标题】:Signal handlers reset every time信号处理程序每​​次都会重置
【发布时间】:2019-06-01 12:08:04
【问题描述】:

我正在编写一个执行以下操作的 C 程序:

监控哪些信号发送给它。计算 SIGUSR1 和 SIGUSR2 已发送的次数。在发送 SIGTERM 时终止,但首先打印出 SIGUSR1 和 SIGUSR2 已发送的次数。

请注意,这是课堂上的问题,所以它不应该真的有任何用途,只是为了测试我们。此外,除了上述三个之外,不会发送其他信号。

这是我得到的:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

int sigUsr1Count = 0;
int sigUsr2Count = 0;

static void sighandler(int signum){
    switch(signum){
        case SIGUSR1:
            sigUsr1Count++;
            break;
        case SIGUSR2:
            sigUsr2Count++;
            break;
        case SIGTERM:
            printf("%d %d\n", sigUsr1Count, sigUsr2Count);
            exit(0);
    }
}

int main(int argc, char ** argv){
    pid_t mypid = getpid();
    fprintf(stderr, "My PID is %d\n", mypid);

    struct sigaction sa;
    sa.sa_flags = 0; 
    sigemptyset(&sa.sa_mask);
    sa.sa_handler = sighandler;
    iAssert(-1 != sigaction(SIGUSR1, &sa, NULL), "sigaction1 failed");
    iAssert(-1 != sigaction(SIGUSR2, &sa, NULL), "sigaction1 failed");
    iAssert(-1 != sigaction(SIGTERM, &sa, NULL), "sigaction1 failed");

    while(true){
        fprintf(stderr, "Waiting...\n");
        sleep(3);
    }

    return 0;
}

我在某个论坛上读到,当使用sigaction 时,信号处理程序不会重置为默认值,除非sa_flags 字段设置为SA_RESETHAND。但是,我的情况似乎并非如此。 (手册页描述了SA_RESETHAND 标志,但没有明确说明在省略它的情况下的操作。)

当我运行程序时,它只会在第一次发送 SIGUSR1 或 SIGUSR2 时转到我的处理程序,之后程序以消息终止:

User defined signal 1 (or 2)

从这个意义上说,程序仅在以下情况下输出正确的值:SIGUSR1 和 SIGUSR2 根本没有发送,或者它们中的每一个都最多发送一次。

iAssert 宏 & 函数:

#define iAssert(cond, msg) crash(cond, msg, __LINE__)
void crash(bool cond, char * msg, int line){
    if(!cond){
        perror(msg);
        fprintf(stderr, "at line %d\n", line);
        exit(EXIT_FAILURE);
    }
}

我已经尝试过的编译方法(每个都一样):

gcc 1.c
gcc -std=c99 1.c
gcc -std=c11 1.c

有什么想法吗?

谢谢。

【问题讨论】:

  • 我在某处读过”希望您指的是手册页 (man sigaction)?
  • 是和不是。在手册页中,它说添加该标志将导致处理程序被重置,但它并没有说不添加它不会这样做。在另一个 Linux 论坛上,我专门读到不设置它会导致处理程序不被重置。
  • 一旦我添加了足够的样板文件以使此代码编译为 C++,它就可以为我工作。您使用的是什么操作系统和/或发行版/版本?
  • 这是elementaryOS Juno。但我不确定这是否与发行版有关。我还尝试在我大学的服务器(一个在线评分器应用程序)上运行此代码,并且程序的行为完全相同。
  • 你没有初始化 sa.sa_flagssa 变量在 stack 上,所以它可能包含碰巧在那里的任何垃圾(包括 SA_RESETHAND) .修复该错误 (sa.sa_flags = 0; sigemptyset(&amp;sa.sa_mask)),然后编辑问题。另请注意,您不应从信号处理程序中调用printf

标签: signals


【解决方案1】:

好吧,既然所有 cmets 都同样无用(没有冒犯),我决定采用不同的方法。

我使用了signal 系统调用,而不是sigaction。我还修改了一些其他的东西。由于printf 不是信号安全函数,我引入了一个名为shouldStop 的全局变量,默认设置为false,然后使用SIGTERM 处理程序更改为true。然后在main 函数内完成打印。

代码如下:

int sigUsr1Count = 0;
int sigUsr2Count = 0;

bool shouldStop = false;

static void sighandler(int signum){
    switch(signum){
        case SIGUSR1:
            sigUsr1Count++;
            break;
        case SIGUSR2:
            sigUsr2Count++;
            break;
    }
}

static void termhandler(int signum){
    shouldStop = true;
}

int main(int argc, char ** argv){
    pid_t mypid = getpid();
    fprintf(stderr, "My PID is %d\n", mypid);

    iAssert(SIG_ERR != signal(SIGUSR1, sighandler), "signal1 failed");
    iAssert(SIG_ERR != signal(SIGUSR2, sighandler), "signal2 failed");
    iAssert(SIG_ERR != signal(SIGTERM, termhandler), "signal3 failed");

    do{

    }while(!shouldStop);
    printf("%d %d\n", sigUsr1Count, sigUsr2Count);

    return 0;
}   

它可以按照我想要的方式正常工作。

还是谢谢。

【讨论】:

    猜你喜欢
    • 2017-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-29
    • 2017-04-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多