4

很长时间以来,我一直在寻找解决问题的方法,这就是我求助于您的原因:

考虑这段代码:

static char done = 0;
static void sigHandler(void)
{
    done = 1;
}

int user_input()
{
    return (getchar() == 'q') ? 0 : 1;
}

int main(void)
{
    signal(SIGTERM, sigHandler);
    signal(SIGINT, sigHandler);
    while (user_input() != 0 && !done)
        usleep(1000);
    printf("exiting\n");
    return 0;
}

预期行为:当用户输入 q 然后进入时程序退出。如果CTRL+C被按下,它会被 sigHandler 函数捕获,该函数将标志“done”设置为 1 并退出程序。

观察到的行为:CTRL+C字符被 getchar() 调用吃掉了,sigHandler 函数永远不会执行。当CTRL+C然后按 enter 时,调用 sigHandler 函数并退出程序。

有更多经验和知识的人可以帮助我吗?

感谢您的输入 :)

4

3 回答 3

6

代码实际上按预期工作 -done在您从 返回之前不会测试标志user_input(),这就是为什么您需要在 control-C 之后输入一个附加字符的原因。

如果您想在getchar获得 control-C 时中止调用,那么您可能不得不做一些丑陋的事情,例如使用setjmp/ longjmp

于 2011-11-02T09:51:17.267 回答
6

Ctrl-C 字符被getchar()调用吃掉,sigHandler 函数永远不会执行。

Ctrl-C 不会被getchar;吃掉 它导致信号被传递并sigHandler运行。这设置done并返回。只有 thengetchar调用,它吃掉换行符,然后被检查,done所以程序退出。

顺便说一句,信号处理程序接受一个int参数,而不是void.

于 2011-11-02T09:51:52.873 回答
6

有一种方法可以在不诉诸丑陋黑客的情况下中止呼叫(与 Paul R 所说的相反)。您应该使用sigaction()with sa_flagsset to0而不是signal().

此外,信号(2)手册说:

避免使用它:使用sigaction (2) 代替。

#include <stdio.h>
#include <signal.h>
#include <string.h>
#include <errno.h>

static char done = 0;
static void sigHandler(int signum)
{
    done = 1;
}

int user_input()
{
    return (getchar() == 'q') ? 0 : 1;
}

int main(void)
{
    struct sigaction sa;
    memset(&sa, 0, sizeof(struct sigaction));
    sa.sa_handler = sigHandler;
    sa.sa_flags = 0;// not SA_RESTART!;

    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGTERM, &sa, NULL);

    while (user_input() != 0 && !done)
        usleep(1000);
    printf("exiting\n");
    return 0;
}

通常,在捕获和处理信号后,大多数(我不确定是否不是全部)系统调用将重新启动。这样,在处理完 sigint 信号后,您的 getchar 函数将继续执行,就好像什么都没发生一样。您可以通过调用 sigaction 来更改此行为sa_flags=0

这样,在处理完 SIGINT 之后,getchar将返回-1并且 errno 将被设置为“Interrupted system call”(我现在不记得常量名称了)。

您还必须重写您的 user_input() 函数来处理返回 -1 时的情况。

于 2011-11-02T19:18:52.327 回答