// sigdemo1.c - show how a signal handler works.
// - run this and press Ctrl-C a few times
// 在第一次等待答复时,按下 Ctrl-C 只会出现 ^C 字符。
// 之后再按
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
extern void f(int);
int main(void) {
signal(SIGINT, f);
for (int i = 0; i < 5; ++i) {
printf("blah blah blah\n");
sleep(1);
}
return EXIT_SUCCESS;
}
extern void f(int signum) {
printf("\tInterrupted! OK to quit (y/n)?");
int c = getchar();
if (c == EOF || c == 'y') {
exit(EXIT_SUCCESS);
}
fflush(stdin);
}
在第一次发送 SIGINT
之后,输入 n
并回车,第二次中断时却在输出 Interrupted! OK to quit (y/n)?
之后就不接受输入,直接继续输出 blah blah blah
, 第三次中断时才会接收输入。
怀疑 fflush(stdin)
没生效,求解。
之前的回答错了呜呜呜 QAQ
是这样子的,fflush(stdin) 在C标准里是行为未定义的,但是 glibc 说自己实现了这么个功能so。但是 glibc 2.20 骗人啦!它看看是不是存在未读取的数据,如果是,那么 lseek 回去!但很显然,连接到终端的 stdin 是不支持 lseek 的,所以就失败啦。glibc 只好忽略掉了。然后置位 _offset
字段为 _IO_pos_BAD
加粗文字。
c
int _IO_new_file_sync (fp) _IO_FILE *fp; { _IO_ssize_t delta; int retval = 0; /* char* ptr = cur_ptr(); */ if (fp->_IO_write_ptr > fp->_IO_write_base) if (_IO_do_flush(fp)) return EOF; delta = fp->_IO_read_ptr - fp->_IO_read_end; if (delta != 0) { #ifdef TODO if (_IO_in_backup (fp)) delta -= eGptr () - Gbase (); #endif _IO_off64_t new_pos = _IO_SYSSEEK (fp, delta, 1); if (new_pos != (_IO_off64_t) EOF) fp->_IO_read_end = fp->_IO_read_ptr; #ifdef ESPIPE else if (errno == ESPIPE) ; /* Ignore error from unseekable devices. */ #endif else retval = EOF; } if (retval != EOF) fp->_offset = _IO_pos_BAD; /* FIXME: Cleanup - can this be shared? */ /* setg(base(), ptr, ptr); */ return retval; }
不知道这个是干什么的,反正 getchar 不理它:
c
int getchar (void) { int result; _IO_acquire_lock (_IO_stdin); result = _IO_getc_unlocked (_IO_stdin); _IO_release_lock (_IO_stdin); return result; }
c
#define _IO_getc_unlocked(_fp) \ (_IO_BE ((_fp)->_IO_read_ptr >= (_fp)->_IO_read_end, 0) \ ? __uflow (_fp) : *(unsigned char *) (_fp)->_IO_read_ptr++)
PS: 在信号处理器里使用不可重入函数,是可能出问题的。
PPS: 不知道为什么,我这里在按第二次 Ctrl-C 时程序就被杀掉了。因为C库调用 rt_sigaction 时设置了 SA_RESETHAND 标志。