Причина получает () для выхода на SIGINT в C
Я пишу простую программу на C, которая читает по одной строке текста за раз с клавиатуры (в цикле), используя функцию gets().
Цикл должен немедленно завершиться, если пользователь нажимает CTRL-C. Я знаю, как написать обработчик sig, который может установить флаг для выхода из цикла... но как мне сделать так, чтобы функция gets() сразу же возвращалась при поступлении этого сигнала?
1 ответ
Вы должны использовать select()
чтобы проверить, доступны ли данные перед чтением из stdin:
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
(errno EINTR) после возврата из обработчика сигнала, тогда как read()
(вызывается (f) gets) будет автоматически возобновлено.
С 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 (и даже версий ядра), поэтому первая версия является более безопасным и более переносимым / надежным способом.