В моем многопоточном приложении GUI у меня есть следующий код обработки сигналов. Я хочу улучшить этот код, чтобы он был корректным и безопасным для многопоточности, но есть некоторые вещи, которые я не совсем понимаю в обработке сигналов:
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);
}
Я регистрирую обработчики сигналов в моей функции инициализации:
// register signal handlers
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
signal(SIGUSR1, signal_handler);
Будьте очень осторожны: как Сигнал (7) страница говорит, только очень мало функций ( «Асинхронный сигнал безопасно» из них) могут (прямо или косвенно) вызываться внутри обработчиков сигналов. Связанные с мьютексом функции, вероятно, не должны вызываться в обработчиках сигналов. Смотрите также Pthreads (7)
Вы могли бы рассмотреть возможность установки volatile sigatomic_t переменной в вашем обработчике сигналов, и время от времени проверяйте значение этого флага.
Если у вас есть атомы C ++ 11 (или C11), например, C ++ 11 станд :: атомное или C11 <stdatomic.h>
, ты мог бы сделать это volatile
переменная также атомная в этом смысле. Затем используйте средства атомной нагрузки, чтобы проверить это.
Документация Qt предлагает следующий трюк: создать трубы (2) самостоятельно при запуске, а затем ваш обработчик сигнала написать (2) ( write
syscall указан как безопасный для асинхронного сигнала) один (или более) байт [s] для канала к тому же процессу, и ваш цикл событий GUI Опрос (2) конец чтения этой трубы.
Linux-специфические способ обработки сигналов с помощью Qt может заключаться в использовании signalfd (2) вероятно с QSocketNotifier (несмотря на название, он работает с дескрипторами файлов, которые могут только Розетки). С другими инструментами GUI вы, вероятно, также можете добавить дескриптор файла (один из signalfd
или же pipe
) быть опрошенным.
Простой способ обработки сигналов в многопоточном приложении — создать один поток в качестве отдельного потока обработки сигналов. Все сигналы интереса блокируются в каждом потоке; обработчики сигналов не установлены; и вызов потока обработки вызовов sigwaitinfo()
в цикле, действуя на сигналы, как они получены.
Это означает, что вам не нужно беспокоиться о том, являются ли функции, которые вы хотите вызвать, асинхронному сигнал безопасно или нет, потому что сигналы не обрабатываются в обработчиках сигналов — они обрабатываются синхронно вашим выделенным потоком обработки сигналов, который может вызывать любую функцию, которая ему нравится (например, он может использовать обычные функции синхронизации pthreads для пробуждения другого потока ).
Этот ответ относится к потокам POSIX (pthreads
).
Ссылаясь 1:
Сигналы могут обрабатываться на уровне потока, да. Если более чем один поток процесса обрабатывает сигнал и сигнал отправляется процессу, но в конкретный поток не определено, какой обработчик потока будет обрабатывать сигнал. (увидеть man pthread_kill()
для деталей)
Ссылаясь 2:
Обработчик сигнала будет освобожден в контексте потока, который его установил. Это включает в себя основной поток.
Ссылаясь 3:
Если в один и тот же процесс отправлено более одного сигнала одного типа, они могут быть сконцентрированы в одном сигнале, прежде чем покинуть очередь сигналов. Могу ли я признать, что это может быть дифференцировано до уровня потока, я точно не знаю.
Ссылаясь на 4:
Если в игре задействованы общие ресурсы: да, по крайней мере для тех частей кода обработчиков, которые одновременно получают доступ к этим ресурсам. Более того, это также зависит от логики, которую вы пытаетесь реализовать.