Как заблокировать все СИГНАЛЫ в потоке БЕЗ использования SIGWAIT?

#c #unix #pthreads #signals

#c #unix #pthreads #сигналы

Вопрос:

У меня есть основное приложение, которое создает отдельный поток для обработки сообщений из очереди. У меня возникает проблема в AIX, когда я нажимаю CTRL-C, поскольку, похоже, некоторые «дескрипторы соединений» в потоке становятся недействительными. У меня есть перехват завершения работы в основной программе, перехватывающий SIGINT, но в AIX, похоже, он каким-то образом отправляет сигнал и в поток … хотя, судя по тому, что я слышу, это на самом деле невозможно…

По сути, я хотел бы знать, хочу ли я, чтобы ОСНОВНОЕ приложение обрабатывало ВСЕ интересующие меня сигналы и чтобы потоки НИКОГДА не обрабатывали ни одного signals…is это «хорошая практика»?

Если да, то как я могу НЕ использовать «sigwait» в thread…in факт, я не хочу никакого «сигнального кода» в потоке / -ах…они просто не должны получать никаких сигналов вообще.

Я удалил все сигналы:

 sigemptyset(amp;set);
  

И установили SIG_BLOCK

 s = pthread_sigmask(SIG_BLOCK, amp;set, NULL);
  

Итак, вот фиктивная тестовая программа:

 #include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>

#define handle_error_en(en, msg) do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)

static void * threadMainLoop(){
    //Here I do not want the thread to use "sigwait"....
    while(running == TRUE){
      //do some thread work and never have any signals come in
    }
}

void shutdownHook(int sig){
    printf("nCtrl-C pressed....shutdown hook in main...n");
}

void signalErrorHandler(int signum){
    printf("nSignal error handler in main...n");
}

int main(int argc, char *argv[]){
    pthread_t thread;
    sigset_t set;
    int s;

    //Catch the following signals in the MAIN thread
    (void) signal(SIGINT, shutdownHook);
    (void) signal(SIGSEGV, signalErrorHandler);
    (void) signal(SIGBUS, signalErrorHandler);
    (void) signal(SIGILL, signalErrorHandler);
    (void) signal(SIGTERM, signalErrorHandler);
    (void) signal(SIGABRT, signalErrorHandler);

    sigemptyset(amp;set); //BLOCK all signals

    s = pthread_sigmask(SIG_BLOCK, amp;set, NULL);
    if (s != 0)
        handle_error_en(s, "pthread_sigmask");

    s = pthread_create(amp;thread, NULL, amp;threadMainLoop, (void *) NULL);
    if (s != 0)
        handle_error_en(s, "pthread_create");  

    pause();
}
  

Если я просто создаю поток и у меня есть, например, обработчик сигнала SIGINT в ГЛАВНОМ потоке, но для потока НЕ установлен параметр SIG_BLOCK, и пользователь нажимает CTRL-C …. влияет ли поток вообще, даже если обработчик сигнала в главном потоке выполняется? Похоже, это то, что я вижу в AIX;-(

Спасибо за помощь, высоко ценится

Линтон

Ответ №1:

С s = pthread_sigmask(SIG_BLOCK, amp;set, NULL); вы ничего не блокируете.

Использовать:

 sigfillset(amp;set);
sets = pthread_sigmask(SIG_SETMASK, amp;set, NULL);
  

Если вы хотите заблокировать каждый сигнал или явно добавить сигналы, которые вы хотите заблокировать, в set , если вы используете SIG_BLOCK.

После того, как вы создали потоки, вам нужно восстановить маску сигнала, иначе никакие потоки не смогут перехватить какой-либо сигнал.

Однако, глядя на ваш предыдущий вопрос, может оказаться, что поток, перехватывающий сигнал, не справляется с прерыванием. То есть, если вы заблокированы при выполнении системного вызова, и поступает сигнал, этот системный вызов прерывается. Некоторые операционные системы по умолчанию автоматически вызывают системный вызов повторно, некоторые возвращают ошибку и присваивают errno значение EINTR, которое должно обработать приложение — и могут произойти плохие вещи, если это не будет обработано.

Вместо этого установите ваши обработчики сигналов с помощью sigaction() вместо signal() и установите SA_RESTART флаг, который приведет к автоматическому перезапуску системных вызовов в случае, если они были прерваны сигналом.

Комментарии:

1. Привет, но я установил «s = pthread_sigmask(SIG_BLOCK, amp;set, NULL);» и проверил с помощью CTRL-C, что поток не получает сигнал? Это означает, что он блокирует его? Если я добавлю «sigaddset(amp;set, SIGINT);», то поток получит сигнал. Простите меня, если я здесь ошибаюсь… Я все еще учусь ..;-) Спасибо за помощь 😉

2. Немного обновил ответ.. Маска сигнала — это сигналы, которые не могут быть вызваны. Итак, если вы используете sigaddset(amp;set, SIGINT); pthread_sigmask(SIG_BLOCK, amp;set, NULL); , SIGINT будет установлен в отдельной маске, и это означает, что поток его не получит. Если вы создаете новый поток, этот поток наследует маску сигнала от потока, который его создал.

3. Обратите внимание, что если вы хотите, чтобы новый поток запускался с замаскированными сигналами (обычно это необходимо, чтобы избежать неприятных условий гонки), вам нужно заблокировать сигналы перед вызовом pthread_create , а затем восстановить старую маску сигнала в исходном потоке после pthread_create возврата.

4. @LyntonGrice, когда вы блокируете сигнал и он отправляется в поток, сигнал остается ожидающим отправки в поток. Когда вы позже разблокируете поток, сигнал будет доставлен. Если вы не хотите, чтобы сигнал доставлялся, вы должны игнорировать его, а не блокировать.

Ответ №2:

Все еще неправильный дизайн. Не используйте CTRL C для контролируемой остановки приложения. Используйте правильно разработанное приложение-контроллер, которое будет доступно через CORBA, RMI или какой-либо другой метод для взаимодействия с пользователем и управления фоновым приложением.

Веселитесь, ребята…