Подтвердить что ты не робот

Функция обработчика сигнала в многопоточной среде

В моем многопоточном графическом приложении у меня есть следующий код обработки сигналов. Я хочу улучшить этот код, чтобы он был корректным и потокобезопасным, но есть некоторые вещи, которые я не совсем понимаю при обработке сигналов:

  • - это сигнал, обрабатываемый на уровне процесса или потока (могу ли я иметь обработчики сигналов, специфичные для потока)?
  • в котором контекст потока выполняет функцию 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);
4b9b3361

Ответ 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:

Если в игру задействованы общие ресурсы: да, по крайней мере, для частей кода обработчиков, обращающихся к этим ресурсам одновременно. И, кроме того, это также зависит от логики, которую вы пытаетесь реализовать.