2012-04-03 2 views
1

У меня есть небольшая программа, которая открывает файл и выполняет некоторую операцию над ним. Я подписался закрытие файла окончания программы следующим образом:on_exit и CTRL + C

static 
void exit_handler (int ev, void *arg) 
{ 
    fprintf(stderr, "bye %d\n", WEXITSTATUS(ev)); 
    fclose((FILE *)arg); 
} 

int main (int argc, char *argv[]) 
{ 
    FILE *out; 

    ... 

    out = fopen(argv[1], "wt"); 
    if (out == NULL) { 
     perror("Opening output file"); 
     exit(EXIT_FAILURE); 
    } 
    on_exit(exit_handler, out); 

    ... 
} 

Попытка выполнить это я заметил, что он работает правильно, только если программа завершается нормально. В случае CTRL + C (SIGINT) Обратный звонок exit_handler не выполнен.

Разве это не странно? Должен ли я связать вызов exit(EXIT_FAILURE) с обработчиком сигнала для SIGTERM? Какова наилучшая практика в этом случае?

+1

Обратите внимание, что по умолчанию для большинства TTY CTRL + C отправит 'SIGINT' в процесс переднего плана, а не' SIGTERM'. –

+0

@JonathonReinhart правильный. Я исправил это, спасибо. – Dacav

ответ

4

Прежде всего, on_exit не указан POSIX (atexit с той же семантикой есть). Во-вторых, руководство Linux говорит:

Функция on_exit() регистрирует данную функцию, вызываемую при нормальном завершении процесса, будь то через выход (3) или с помощью возвращения из программы Мейн().

убитый сигнал не является нормальным выходом для процесса, чтобы обратные вызовы, установленные с on_exit и atexit не неявно вызываются.

+0

Хорошая точка для комментария POSIX. – Dacav

+0

Фактически 'atexit' определяется стандартом ISO C, поэтому он существует даже для не-POSIX-реализаций. –

3

on_exit не будет вызываться для сигналов SIGTERM. Вам нужно добавить обработчик для него с signal. Например:

void signalHandler(void) 
{ 
    ... 
} 

int main(void) 
{ 
    signal(SIGTERM, signalHandler); 
} 

отметить также, что SIGKILL не может быть перехвачено дизайном.

+0

«signalHandler» здесь может просто 'exit (0)', который вызывается обработчиками 'atexit'. –

2

От man page из on_exit,

Функция on_exit() регистрирует данную функцию, которая будет вызвана при нормального завершения процесса, будь то через выход (3) или с помощью возвращения из программы с главным().

Так что вам нужно подключить в явной форме обработчик SIGTERM с использованием специфических функций из signal.h

Что-то на линиях

struct sigaction action; 

memset (&action, 0, sizeof(action)); 
action.sa_handler = sigterm_handler; 

if (sigaction(SIGTERM, &action, 0)) 
{ 
    perror ("sigaction"); 
    return 1; 
} 

/* SIGTERM handler. */ 
static void sigterm_handler (int sig) 
{ 
... 
} 
2

Нет, и на самом деле то, что вы хотите, это невозможно. Сигнал, сгенерированный Ctrl + C, составляет асинхронный, что означает, что это может происходить между любыми двумя машинными инструкциями в вашей программе в зависимости от того, когда нажата комбинация клавиш Ctrl + C. Таким образом, если ваша программа не полностью избегает вызова несинхронных функций, не связанных с синхронизацией сигналов, в любом месте основного потока программы, незаконно вызывать неактивные функции, связанные с асинхронным сигналом, из обработчика сигнала. exit является асинхронным сигналом-небезопасным, так как это большая часть активности очистки по умолчанию, которую он выполняет (например, сброс/закрытие открытых файлов). Я бы ожидал, что функция atexit, которую вы хотите зарегистрировать (atexit, а не on_exit, является правильным именем для этой функции) также захочет делать асинхронные сигналы-небезопасные вещи.

Если вам необходимо выполнить очистку при выходе на основе сигнала, вам необходимо установить обработчик сигнала, который сам не имеет exit, но вместо этого устанавливает глобальный флаг волатильности, который будет проверяться вашим основным потоком программы (и exit, если это правда).

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