jul*_*n.d 4 c unix signals getchar
我一直在寻找解决我问题的方法很长一段时间,这就是我转向你的原因:
考虑一下这段代码:
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;
}
Run Code Online (Sandbox Code Playgroud)
预期行为:当用户输入q然后输入时,程序退出.如果按下CTRL+ C,则由sigHandler函数捕获它,该函数将标志'done'设置为1并退出程序.
观察到的行为:getchar()调用会使用CTRL+ C字符,并且永远不会执行sigHandler函数.当CTRL+ C,然后按Enter键,则sigHandler函数被调用,程序退出.
有经验和知识的人可以帮助我吗?
感谢您的输入 :)
代码实际上正在按预期工作 - 您done在返回之前不会测试该标志user_input(),这就是您需要在control-C之后输入其他字符的原因.
如果你想getchar在你得到一个控件C时中止调用,那么你可能不得不做一些丑陋的事情,例如使用setjmp/ longjmp.
getchar()调用会吃掉Ctrl-C字符,并且永远不会执行sigHandler函数.
Ctrl-C不被吃掉getchar; 它导致信号被传递和sigHandler运行.这设置done并返回.只有这样被getchar调用,它吃得换行符和之后,done被选中状态,以便在程序退出.
顺便说一句,信号处理程序接受一个int参数,而不是void.
有一种方法可以在不诉诸丑陋黑客的情况下中止调用(与 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;
}
Run Code Online (Sandbox Code Playgroud)
通常,在捕获和处理信号后,大多数(我不确定如果不是全部)系统调用将重新启动。这样,在处理完 sigint 信号后,您的 getchar 函数将继续执行,就好像什么都没发生一样。您可以通过调用 sigaction 来更改此行为sa_flags=0。
这样,在处理 SIGINT 后,getchar将返回-1并且 errno 将设置为“中断的系统调用”(我现在不记得常量名称)。
您还必须重写 user_input() 函数来处理返回 -1 的情况。