Всем здравствуйте. Я расскажу о различных, подчас интересных, эффектах, которые возникают при работе с POSIX сигналами в Windows. Затаривайтесь Вискасом и вперёд. Конечно же не могу не упомянуть гибкость механизма сигналов POSIX. Этот механизм реализует подобие парадигмы событийного программирования в C#, чем он, собственно, и интересен. Обычно, в коде, написанном на C/C++ мы вызываем функции ядра, например внутри getch(). А вот когда ядро вызывает нас, происходят всякие интересные эффекты: такие как асинхронные вызовы и произвольная логика программы, изменение способа обработки исключительных ситуаций. Чем то напоминает callback. Здесь мы можем отреагировать на действия пользователя, сигналы от ОС или исключительную ситуацию, возникшую в программе. Программирование происходит прозрачно, т.е. мы можем, например, написать обработчик SIGABRT и красиво изменить способ обработки неперехваченных исключений без исследования исходного кода всей программы, т.к. писать обработчики и генерировать в них специально этот сигнал не нужно, он генерируется сам. Но такая гибкость обусловлена тем, что есть некоторые, не совсем очевидные, аспекты. Я продемонстрирую несколько экспериментов с сигналами, в которых обнаруживаются не совсем очевидные вещи. В качестве примеров я выбрал обработчики сигналов SIGINT и SIGABRT. Обработчик SIGINT вызывается асинхронно, в ответ на нажатие клавиш CTRL+C. Обработчик SIGABRT вызывается в ответ на необработанную исключительную ситуацию, но не всегда. Я объясню особенности, возникающие в зависимости от способа генерации сигналов и наличия отладчика. Обратите внимание на то, что все эксперименты проводились в Windows, а исходный код компилируется как код C++. Обработчики сигналов запускаются в разном контексте в зависимости от того, каким образом сгенерирован сигнал. Обработка исключения, в зависимости от контекста обработчика сигнала. Обработчик сигнала SIGABRT вызывается, если программа выполняется не под отладчиком. Исходный код программы Случай, когда сигнал возбужден программой Обработчик запускается в контексте нашей программы. Вывод Смотрим стек вызовов Мы видим, что вызов обработчика происходит в основном потоке, посредством библиотеки выполнения C Runtime Случай, когда сигнал возбужден ядром. Это стандартная ситуация, когда сигнал SIGINT возбуждается при нажатии на клавиатуре CTRL+C при работе консольных приложений. Обработчик запускается в контексте ядра в отдельном потоке. Вывод Смотрим стек вызовов потока 2848 Мы видим, что вызов обработчика происходит в потоке kernel32.dll, посредством библиотеки выполнения C Runtime Здесь в том случае, если сигнал сгенерирован программой, возбужденное исключение попадёт в блок try/catch. Причина следует из особенностей, которые я описал в п.1. При возбуждении исключения происходит раскрутка стека, т.е. поиск обработчиков в генерирующей сигнал (и фактически вызвавшей её обработчик) функции. Вывод А вот если SIGINT сгенерирован ядром, исключение не найдёт своего обработчика и отправится в отладчик, либо будет сгенерирован SIGABRT. Точнее найдёт, возможно, в неграх ядра есть SEH обработчик верхнего уровня (системный), до которого исключение в конце концов добирается и уже этот обработчик производит фактически вызов обработчика SIGABRT, который находится в нашей программе. Однако, зафиксировать этот факт при отладке не представляется возможным. Возбуждаем пустое исключение. Если программа выполняется под отладчиком, неперехваченное исключение попадает в отладчик, т.к. никаких обработчиков для такого исключения не предусмотрено. Вывод Отладчик Если программа выполняется без присоединённого отладчика, происходит генерация SIGABRT Вывод Итоги: Если мы генерируем сигнал в программе, то обработчик сигнала вызывается как обычная функция Если сигнал генерирует ядро, то обработчик сигнала вызывается в отдельном потоке Если программа выполняется под отладчиком, все сгенерированные и необработанные исключения перехватывает отладчик.  Если программа выполняется без отладчика, вызывается обработчик сигнала SIGABRT Програмист, хаброридер