Обработка SIGQUIT с помощью sigwait

Я пишу многопоточную программу, которую нужно завершить следующей строкой bash:

killall -QUIT -w procname

Я решил использовать поток для получения некоторых сигналов, которые мне нужно обработать, таких как SIGQUIT и SIGUSR1, и игнорировать SIGQUIT в других. Чтобы игнорировать сигнал, я написал это:

struct sigaction s;
s.sa_handler=SIG_IGN;
if((sigaction(SIGQUIT,&s,NULL))==-1) {   
    perror("sigaction");
    return -1;
    }

И я написал следующий код в потоке, предназначенном для ожидания сигналов (handlerrno — это функция для проверки errno и выхода):

sigset_t threadset;
int err, sig;
if(sigfillset(&threadset)==-1) handlerrno("Sigfillset thread stats");
if(sigdelset(&threadset,SIGQUIT)==-1) handlerrno("Sigdelset thread stats");
if(sigdelset(&threadset,SIGINT)==-1) handlerrno("Sigdelset thread stats");
if(sigdelset(&threadset,SIGTERM)==-1) handlerrno("Sigdelset thread stats");
if(sigdelset(&threadset,SIGUSR1)==-1) handlerrno("Sigdelset thread stats");
if((err=pthread_sigmask(SIG_SETMASK,&threadset,NULL))!=0)        
   handlerror(err,"Set sigmask thread stats");
if((err=sigwait(&threadset,&sig))!=0) handlerror(err,"Sigwait");
//I handle the signals here

Однако, когда я запускаю SIGQUIT из оболочки, поток, предназначенный для ожидания сигналов, кажется застрявшим в sigwait(), поэтому я действительно не знаю, что происходит и какой поток получает сигнал. Что-то не так с кодом? Спасибо!


person Gixuna    schedule 04.08.2017    source источник


Ответы (1)


Маски игнорирования распространяются на весь процесс. После вызова sigaction SIQUIT никогда не станет ожидающим ни в одном потоке, и поэтому sigwait будет заблокирован навсегда.

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

Затем поток обработки должен иметь возможность удалить сигнал из очереди, несмотря на то, что он заблокирован.

(Я не уверен, что ваш выбор терминирующего сигнала является хорошим. SIQUIT обычно отправляется через Ctrl+\ и, как ожидается, создаст дамп памяти перед завершением. Возможно, SIGTERM будет лучшим выбором.)

person PSkocik    schedule 04.08.2017
comment
Спасибо! Мне нужно завершить процесс таким образом, потому что это задание для университета, поэтому наш преподаватель дал нам тестовый сценарий, чтобы убедиться, что код работает. В любом случае, дело в том, что поток обработки порождается основным потоком, поэтому, если я заблокирую его там, обработка тоже заблокирует его, верно? - person Gixuna; 04.08.2017
comment
Правильный. И если ни один поток не разблокировал его, и у вас есть только один активный вызов sigwait в процессе, вызов sigwait должен получить его. - person PSkocik; 04.08.2017