我正在编写一个简单的C程序,它使用gets()函数从键盘(循环中)一次读取一行文本。
如果用户按下CTRL-C,则必须立即退出循环。我知道如何编写一个sig处理程序,它可以设置一个标志来退出循环......但是当这个信号到达时,如何使gets()函数立即返回?
答案 0 :(得分:1)
在从stdin读取之前,您应该使用select()
检查数据是否可用:
void handler (int arg) {
// handle signal
}
int main (void) {
char buf[100];
signal(SIGINT, handler);
do {
fd_set f;
FD_ZERO(&f);
FD_SET(fileno(stdin), &f);
int st = select(fileno(stdin)+1, &f, NULL, NULL, NULL);
if (st == 1) {
fgets(buf, sizeof(buf), stdin);
// Handle input
}
} while (st >= 0);
exit(EXIT_SUCCESS);
}
从信号处理程序返回后, select()
将返回-1
(错误EINTR),而read()
(由(f)获取)将自动恢复。
使用linux,还有另一种可能使用sigaction()
:
void handler (int arg) {
// handle signal
}
int main (void) {
char buf[100], *p;
struct sigaction sa = { .sa_handler = handler, .sa_flags = 0, .sa_mask = 0 };
sigaction(SIGINT, &sa, NULL);
do {
p = fgets(buf, sizeof(buf), stdin);
// handle input
} while (p);
printf("Byebye\n");
exit(EXIT_SUCCESS);
}
由于信号处理程序的SA_RESTART
中未指定标记sa_flags
,因此慢设备上的read()
(即终端,管道,套接字) )也会以-1 (EINTR)
返回(另见信号(7))。
虽然稍微简单一些,但不同的unix-flavors(甚至内核版本)之间的行为可能会有所不同,因此第一个版本是更安全,更便携/可靠的方式。