2011-11-27 3 views
3

У меня есть следующий код. Когда я скомпилирую его с расширениями gnu (-std=gnu99), программа закроет 5 SIGINT до окончания (чего я ожидаю). При компиляции без него (-std=c99) заканчивается после второго (и выводится только одна строка).Сигналы - c99 vs gnu99

Что мне не хватает?

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

int int_stage = 0; 
int got_signal = 0; 

void sigint(int parameter) 
{ 
    (void)parameter; 
    got_signal = 1; 
    int_stage++; 
} 

int main() 
{ 
    signal(SIGINT,sigint); 

    while(1) 
    { 
    if (got_signal) 
    { 
     got_signal = 0; 
     puts("still alive"); 
     if (int_stage >= 5) exit(1); 
    } 
    } 
    return 0; 
} 
+0

Вы должны использовать sig_atomic_t, а не ints для обработки сигналов. Если бы я был вами, я бы избегал всего этого беспорядка и просто использовал сигвайт. – Lalaland

+0

@EthanSteinberg Uh? Прототипом функции является 'void (* func) (int))' в соответствии с C и POSIX. –

+1

@Let_Me_Be: Я считаю, что Этан имеет в виду 'got_signal', а не параметр для вашего обработчика сигналов. – Mat

ответ

6

sigaction(2) Использование вместо signal(2).

страница людей

The Linux имеет это, в частности, в разделе Портативности:

В исходных системах UNIX, когда обработчик, который был установлен с использованием сигнала() был вызван в доставке сигнала , расположение сигнала будет сбрасываться на SIG_DFL, и система сделала , а не блокировать доставку дополнительных экземпляров сигнала. Система V также предоставляет эту семантику для сигнала (). Это было плохо, потому что сигнал мог быть доставлен снова, прежде чем у обработчика был шанс , чтобы восстановить его. Кроме того, быстрые поставки одного и того же сигнала могут приводить к рекурсивным вызовам обработчика.

BSD улучшил эту ситуацию, изменив семантику обработки сигналов (но, к сожалению, молчаливо изменил семантику при создании обработчика с сигналом()). В BSD, когда вызывается обработчик сигнала , расположение сигнала не сбрасывается, а дополнительные экземпляры сигнала блокируются от доставки во время выполнения обработчика.

Ситуация на Linux выглядит следующим образом:

  • сигнал() системный вызов Ядро обеспечивает System V семантику.

  • По умолчанию, в glibc 2 и более поздних версиях, функция wrap() не вызывает систему ядра . Вместо этого он вызывает sigaction (2), используя флаги, которые предоставляют семантику BSD. Это значение по умолчанию - ior предоставляется при условии, что определен макрос проверки функции _BSD_SOURCE. По умолчанию определяется _BSD_SOURCE ; он также неявно определяется, если вы определяете _GNU_SOURCE и можете, конечно, быть эксплицированным - .
    В glibc 2 и более поздних версиях, если макрос проверки функции _BSD_SOURCE не определен, тогда сигнал() предоставляет Семантика системы V. (Неявное определение _BSD_SOURCE по умолчанию не предусмотрено, если один вызывает gcc (1) в одном из своих стандартных режимов (-std = xxx или -ansi) или определяет различные другие функции: тестовые макросы, такие как _POSIX_SOURCE, _XOPEN_SOURCE или _SVID_SOURCE; см feature_test_macros (7).)

Используя std=gnu99, вы получаете BSD семантику. Используя -std=c99, вы получаете семантику System V. Таким образом, обработчик сигнала «переустановлен» в одном случае (BSD), а расположение сигнала сбрасывается обратно в SIG_DFL в другом (System V).

0

Я согласен с Этаном Штейнбергом - «Занятое ожидание» настолько неправильное ...

Но проблема в том, что вы не можете сбросить обработчик сигнала. AFAIK, вы должны сделать это (вызов «сигнал (SIGINT, SIGINT)» снова) с любой версии C.

2

Проблема заключается в том, что сигнал также сбрасывает механизм обработки сигнала, вы должны сбросить SIGINT в качестве сигнала обработчик. Из ручного

В исходных системах UNIX, когда обработчик, который был установлен с использованием сигнала() был вызван с помощью доставки сигнала, расположение сигнала будет сбрасываются в SIG_DFL, и система не сделала блокировать доставку дополнительных экземпляров сигнала. Система V также предоставляет эту семантику для сигнала(). Это было плохо, потому что сигнал мог быть доставлен снова, прежде чем у обработчика появилась возможность восстановить себя. Более того, быстрые поставки одного и того же сигнала могут приводить к рекурсивным вызовам обработчика.

Это как сделать это со старым устаревшим сигналом() вызова. Обратите внимание, что int_stage и got_signal должны быть sig_atomic_t. Вы также можете вызывать только безопасные функции async, посмотрите на список here.

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

sig_atomic_t int_stage = 0; 
sig_atomic_t got_signal = 0; 

void sigint(int parameter) 
{ 
    (void)parameter; 
    got_signal = 1; 
    int_stage++; 
} 

int main() 
{ 
    signal(SIGINT,sigint); 

    while(1) 
    { 
     if (got_signal) 
     { 
     signal(SIGINT,sigint); 
     got_signal = 0; 
     puts("still alive"); 
     if (int_stage >= 5) exit(1); 
    } 
} 
return 0; 
} 

Пожалуйста, учитывайте либо сигмацию, либо сигвайт.

Sigaction будет иметь практически ту же идею, но не вздор с повторной инициализацией обработчика сигналов. Sigwait остановит вашу нить до получения сигнала. Таким образом, для sigwait вы можете вызывать любую функцию или обрабатывать любые данные. Я могу показать вам пример кода, если вы хотите.