Непосредственная проблема заключается в том, что ваш основной l oop всегда сбрасывает обработчик сигнала, и вы недостаточно быстры для генерации этого второго сигнала, прежде чем ваш код сбрасывает расположение SIGINT в handler1.
step what
---- ----------------------------------------
0 main/set SIGINT disposition -> handler1
1 main/sleep(1) -> ...
2 <SIGINT>
3 handler1/set SIGINT disposition -> handler2 // Note: SIGINT delivery is probably
// blocked during handler1()
4 <return to main>
5 main/sleep() -> EINTR
6 main/set SIGINT disposition -> handler1 // Another SIGINT will now do the same
// as before
7 main/sleep(1) -> ...
Вот почему, как вы заметили в другом месте, sleep()
внутри первого обработчика сигнала работает: он дает вам достаточно времени для генерации INT, пока расположение этого сигнала установлено на handler2.
Теперь есть ряд вещи, которые я предлагаю вам изменить в этой реализации.
Вытяните signal()
звонки из вашего основного l oop. Не ясно, что поведение имеет смысл в логах c вашей программы.
Пожалуйста, используйте sigaction()
, а не signal()
. sigaction()
более сложный, и он заставляет вас указать важные вещи, такие как: sleep()
возобновится после сигнала (SA_RESTART)? Будет ли ваш обработчик позволять сигналам прерывать себя (sa_mask
, SA_NODEFER)? Как много вы хотите знать о сгенерированном сигнале (SA_SIGINFO)? Хотите ли вы обработчик «одного выстрела» (SA_RESETHAND)?
Любое использование signal()
должно отвечать на все эти вопросы неявно, и прискорбная историческая реальность заключается в том, что разные платформы имели разные ответы на эти вопросы. Используйте sigaction()
.
Вы также захотите удалить printf()
из ваших обработчиков сигналов .
Пуристы также порекомендуют вам манипулировать volatile sig_atomic_t
переменная внутри обработчика, а не простая int
.