2015-06-26 9 views
0
sigfillset(&set); 
sigdelset(&set, SIGUSR2); 

sigsuspend(&set); 

// signal handler sets a flag 

if(flag == 1) 
    //do something 

В этом случае моя нить только просыпается, когда поставляется SIGUSR2. Однако кажется, что что-то еще заставляет sigsuspend возвращаться, но я не знаю, что, поскольку все остальные сигналы маскируются. Есть ли какие-либо проблемы в этом фрагменте кода?Проблема системного вызова Sigsuspend

Большое спасибо

+0

Пожалуйста, покажите нам [MCVE] (http://stackoverflow.com/help/mcve). – pilcrow

ответ

0

Трудно сказать, что именно не так, не видя остальную часть кода, но есть по крайней мере одна проблема с кодом вы показываете:

Перед возвращением, sigsuspend(2) восстанавливает маску сигнала, которая была активной при ее вызове. Если вы не изменили сигнальную маску процесса соответственно до вызова sigsuspend(2), тогда есть время между возвратом от sigsuspend(2) и тестированием значения flag, где могут быть доставлены другие ожидающие сигналы (или это может быть даже в случае, если новые сигналы генерируются и доставляются). Если эти сигналы пойманы, и обработчик изменит значение flag на другое значение, вы «потеряете» обновление, которое сделал обработчик SIGUSR2.

Например, рассмотрим следующую программу:

#include <stdio.h> 
#include <signal.h> 
#include <stdlib.h> 

volatile sig_atomic_t flag; 

void handler1(int signo) { 
    printf("In handler1\n"); 
    flag = 1; 
} 

void handler2(int signo) { 
    printf("In handler2\n"); 
    flag = 2; 
} 

int main(void) { 
    struct sigaction sigact; 
    sigact.sa_handler = handler1; 
    sigact.sa_flags = 0; 
    sigfillset(&sigact.sa_mask); 

    if (sigaction(SIGUSR1, &sigact, NULL) < 0) { 
     perror("sigaction()"); 
     exit(EXIT_FAILURE); 
    } 

    sigact.sa_handler = handler2; 

    if (sigaction(SIGUSR2, &sigact, NULL) < 0) { 
     perror("sigaction()"); 
     exit(EXIT_FAILURE); 
    } 

    sigset_t mask; 
    sigfillset(&mask); 
    sigdelset(&mask, SIGUSR1); 

    sigsuspend(&mask); 

    printf("%d\n", flag); 

    return 0; 
} 

Он ловит SIGUSR1 и SIGUSR2, блоки каждый сигнал, кроме SIGUSR1, а затем вызывает sigsuspend(2).

Запустить его, а затем отправить его SIGUSR2, а затем SIGUSR1. Это гарантирует, что есть ожидающий сигнал до того, как будет видно и действует SIGUSR1. Это также приводит к SIGUSR2 быть доставлены как только SIGUSR2 разблокирован, что происходит после того, как sigsuspend(2) возвращается (потому что мы не трогали маску сигналов процесса):

[email protected]:~/dev$ kill -SIGUSR2 29755 
[email protected]:~/dev$ kill -SIGUSR1 29755 

Выход:

[email protected]:~/dev$ ./a.out 
In handler1 
In handler2 
2 

Как сделать вы это исправите? Просто убедитесь, что сигнальная маска процесса установлена ​​на ту же маску, что и в sigsuspend(2), так что она не ошибочно восстанавливает маску. Это так же просто, как добавление этого перед вызовом sigsuspend(2):

if (sigprocmask(SIG_SETMASK, &mask, NULL) < 0) { 
    perror("sigprocmask()"); 
    exit(EXIT_FAILURE); 
} 

Итак, обновленную программу:

#include <stdio.h> 
#include <signal.h> 
#include <stdlib.h> 

volatile sig_atomic_t flag; 

void handler1(int signo) { 
    printf("In handler1\n"); 
    flag = 1; 
} 

void handler2(int signo) { 
    printf("In handler2\n"); 
    flag = 2; 
} 

int main(void) { 
    struct sigaction sigact; 
    sigact.sa_handler = handler1; 
    sigact.sa_flags = 0; 
    sigfillset(&sigact.sa_mask); 

    if (sigaction(SIGUSR1, &sigact, NULL) < 0) { 
     perror("sigaction()"); 
     exit(EXIT_FAILURE); 
    } 

    sigact.sa_handler = handler2; 

    if (sigaction(SIGUSR2, &sigact, NULL) < 0) { 
     perror("sigaction()"); 
     exit(EXIT_FAILURE); 
    } 

    sigset_t mask; 
    sigfillset(&mask); 
    sigdelset(&mask, SIGUSR1); 

    if (sigprocmask(SIG_SETMASK, &mask, NULL) < 0) { 
     perror("sigprocmask()"); 
     exit(EXIT_FAILURE); 
    } 

    sigsuspend(&mask); 

    printf("%d\n", flag); 

    return 0; 
} 

Это работает, как ожидалось: это гарантирует, что никакие другие обработчики сигналов не будет выполняться между окном время после sigsuspend(2) возвращается, и вы проверяете flag.

Еще одно важное замечание: я не знаю, как вы настроили обработчик сигналов, но если вы используете signal(2), тогда нет: его семантика зависит от платформы и может не вести себя так, как вы хотите. Вы должны использовать sigaction(2) точно так, как я показываю в примере программы. Строка sigfillset(&sigact.sa_mask) необходима, чтобы убедиться, что когда обработчик сигналов работает, все остальные сигналы по-прежнему блокируются - в противном случае доставка сигнала в середине выполнения обработчика SIGUSR1 может вызвать другой обработчик, который изменил флаг.