Функция обработчика сигнала в многопоточной среде
В моем многопоточном графическом приложении у меня есть следующий код обработки сигналов. Я хочу улучшить этот код, чтобы он был корректным и потокобезопасным, но есть некоторые вещи, которые я не совсем понимаю при обработке сигналов:
- - это сигнал, обрабатываемый на уровне процесса или потока (могу ли я иметь обработчики сигналов, специфичные для потока)?
- в котором контекст потока выполняет функцию signal_handler?
- Можно ли отправить несколько сигналов SIGTERM за короткое время?
- Имеет ли смысл использовать мьютекс для предотвращения параллельного выполнения signal_handler?
void signal_handler(int sig)
{
switch (sig)
{
case SIGTERM:
::wxLogMessage(wxT("SIGTERM signal received ..."));
break;
case SIGINT:
::wxLogMessage(wxT("SIGINT signal received ..."));
break;
case SIGUSR1:
::wxLogMessage(wxT("SIGUSR1 signal received ..."));
break;
default:
::wxLogMessage(wxT("Unknown signal received ..."));
}
// send wxCloseEvent to main application window
::wxGetApp().GetTopWindow()->Close(true);
}
Я регистрирую обработчики сигналов в моей функции init:
// register signal handlers
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
signal(SIGUSR1, signal_handler);
Ответы
Ответ 1
Будьте очень осторожны: поскольку страница signal (7) сообщает, что очень мало функций ( "безопасный для асинхронного сигнала" ) ) могут быть (прямо или косвенно) вызваны внутри обработчиков сигналов. Функции, связанные с Mutex, вероятно, не должны вызываться в обработчиках сигналов. См. Также pthreads (7)
Вы можете рассмотреть возможность установки переменной volatile sigatomic_t в вашем обработчике сигнала и время от времени проверять значение этого флага.
Если у вас есть атомы С++ 11 (или C11), например. С++ 11 std:: atomic или C11 <stdatomic.h>
, вы можете сделать эту переменную volatile
также атомной в этом смысле. Затем используйте средства атомной нагрузки, чтобы проверить его.
Документация Qt предлагает следующий трюк: создать pipe (2) для себя при запуске, затем обработчик вашего сигнала write (2) (syscall write
указан как как безопасный для асинхронного сигнала) одиночный (или более) байт [s] для канала к вашему самому процессу, и ваш цикл событий GUI poll (2 ) прочитанный конец этой трубы.
Linux-специфичный способ обработки сигналов с Qt может заключаться в использовании signalfd (2), вероятно, с QSocketNotifier (несмотря на имя, он работает с файлами с загрязненными файлами, а не только сокетами). С другими инструментами GUI вы, вероятно, можете также добавить файловый дескриптор (один из signalfd
или pipe
) для опроса.
Ответ 2
- Обработчики сигналов - это состояние каждого процесса, то есть все потоки процесса совместно используют один и тот же набор установленных обработчиков сигналов.
- Маски сигналов - это состояние в потоке. Сигналы могут быть заблокированы или разблокированы по каждому потоку.
- Сигналы могут быть потоковыми или потоковыми. Если сигнал направлен на процесс, тогда для его обработки выбирается произвольный поток, который в настоящее время не имеет блокированного типа сигнала.
Простым способом обработки сигналов в многопоточном приложении является создание одного потока в качестве выделенного потока обработки сигналов. Все сигналы, представляющие интерес, блокируются в каждом потоке; никаких обработчиков сигналов не установлено; и поток обработки сигналов вызывает sigwaitinfo()
в цикле, воздействуя на сигналы по мере их приема.
Это означает, что вам не нужно беспокоиться о том, что функции, которые вы хотите вызывать, безопасны для асинхронного сигнала или нет, потому что сигналы не обрабатываются в обработчиках сигналов - они обрабатываются синхронно с помощью вашего выделенного сигнала - (например, он может использовать обычные функции синхронизации pthreads для пробуждения другого потока).
Ответ 3
Этот ответ относится к потокам POSIX (pthreads
).
Ссылаясь на 1:
Сигналы могут обрабатываться на уровне нити, да. Если более одного потока процесса обрабатывает сигнал и сигнал отправляется процессу, но в конкретный поток не определяется, какой обработчик потока обработает сигнал. (подробнее см. man pthread_kill()
)
Ссылаясь на 2:
Обработчик сигнала будет вызываться в контексте потока, который его установил. Это включает в себя основной поток.
Ссылаясь на 3:
Если в один и тот же процесс отправляется более одного сигнала того же типа, они могут быть сконденсированы только в один сигнал перед выходом из очереди сигналов. Я могу не согласиться с тем, может ли это отличаться от уровня нити, о котором я точно не знаю.
Ссылаясь на 4:
Если в игру задействованы общие ресурсы: да, по крайней мере, для частей кода обработчиков, обращающихся к этим ресурсам одновременно. И, кроме того, это также зависит от логики, которую вы пытаетесь реализовать.