2015-06-23 2 views
2

я получаю следующий код, который запутать меня так месивосигнала интерактивного UNIX

static jmp_buf env_alrm; 
static void sig_alrm1(int signo){ 
    longjmp(env_alrm,1); 
} 

unsigned int sleep2(unsigned int nsecs){ 
    if(signal(SIGALRM ,sig_alrm) == SIG_ERR) 
     return(nsecs); 
    if(setjmp(env_alrm) == 0){ 
     alarm(nsecs); 
     pause(); 
    } 
    return(alarm(0)); 
} 
static void sig_int(int); 
int main(void){ 
    unsigned int unslept; 
    if(signal(SIGINT,sig_int) == SIG_ERR) 
     err_sys("signal (sigint) error"); 
    unslept = sleep2(5); 
    printf("sleep2 return ed :%u\n" ,unslept); 
    exit(0); 
} 
static void sig_int(int signo){ 
    int i,j; 
    volatile int k; 
    printf("\nsig_int staring\n"); 
    for(i = 0;i<30000;i++) 
     for(j = 0;j<4000;j++) 
      k += i *j; 
    printf("sig_int finished"); 
} 

в то время как функция сна работает, если я нажимаю Ctrl + C. Что происходит на самом деле? Неужели он проигнорирует SIGALRM и запустит sig_int, а затем выйдет?

ответ

3

Сначала есть два устройства обработки сигналов для SIGINT и SIGALRM в main и sleep2 соответственно. Затем устанавливается тревога, которая доставляет SIGALRM в nsecs (что равно 5) и вызывается pause, который ждет любого сигнала.

Если вы отправляете SIGINT (Ctrl + C), тогда как в sleep2 функции, то его обработчик sig_int сигнал называется и когда он возвращается, он вызывает pause вернуться. Наконец, return(alarm(0)); возвращает количество секунд, оставшихся до ранее настроенного аварийного сигнала, если оно должно быть доставлено.

Так что, если вы отправляете SIGINT в течение 5 секунд (т.е. до того SIGALRM посылается alarm(nsecs) вызова), то sleep2 вернет 5-x секунд (x это примерно количество секунд, прошедших с момента запуска программы).

Это в основном к тому, кто просыпается pause первые: SIGINT отправленного вами или SIGALRM посланного alarm(nsecs) вызова. И на этом будет сделан вывод unslept.


Я вижу, что это пример из книги APUE. Это объясняет, почему здесь используется setjmp/longjmp.

Идея комбинации setjmp/longjmp используется для обеспечения программы не застрял в pause в случае SIGALRM поставляется до тогоpause был вызван. Если setjmp/longjmp не были там, и сигнал SIGALRM обрабатывается до pause(), то pause() будет ждать навсегда сигнала, поскольку он не знает о предыдущем SIGALRM.

В книге (Глава 10 Сигналы) объясняется, почему даже это не идеально, поскольку longjmp (в обработчике SIGALRM) может прервать другие обработчики сигналов.

+1

Последний параграф имеет первостепенное значение для понимания того, что происходит с кодом. Целью с обработчиком для 'SIGINT' является то, что он работает более 5 секунд (отсюда вложенные циклы), и он показывает, как это не является хорошей реализацией' sleep() ', потому что оно отменяет выполнение' sig_int () 'когда запускается' SIGALRM'. Цель этого примера - показать, что даже если 'longjmp' /' setjmp' разрешает условие гонки с помощью 'pause()', они вносят проблему потенциальной отмены других обработчиков в середине выполнения. –

Смежные вопросы