Linux C ловит сигнал на убийство для изящного завершения - PullRequest
16 голосов
/ 11 сентября 2011

У меня есть процесс, использующий сокеты, соединения с базой данных и тому подобное. По сути, это серверный процесс, передающий данные датчиков и веб-интерфейс, и поэтому важно, чтобы приложение, если оно было убито, корректно завершало работу.

Как мне обрабатывать непредвиденные исключения, такие как ошибки сегмента (по крайней мере, для отладки), а также сигналы уничтожения, чтобы я мог закрыть любые соединения и остановить все запущенные потоки, чтобы процесс не оставлял в беспорядке все, что он использует?

Ответы [ 3 ]

12 голосов
/ 11 сентября 2011

Ловить сигналы сложно.Ты должен быть осторожен.Ваш первый шаг - использовать sigaction для установки обработчика сигналов для нужных сигналов.

  • Выберите набор сигналов для ответа и укажите, что они означают для вашего процесса.Например, SIGTERM выходит, SIGHUP перезагружается, SIGUSR1 перезагружается конфигурация и т. Д.

  • Не пытайтесь отвечать на все сигналы и не пытайтесь "очистить"вверх "после сигнала, который указывает на ошибку в вашей программе.SIGKILL не может быть пойман.SIGSEGV, SIGBUS и другие подобные им не должны быть пойманы, если у вас нет ОЧЕНЬ веских причин.Если вы хотите отлаживать, то увеличьте ограничение для дампов ядра - присоединение отладчика к образу ядра гораздо эффективнее, чем то, что вы или я могли бы написать.(Если вы попытаетесь выполнить очистку после SIGSEGV или чего-то подобного, осознайте, что код очистки может привести к дополнительному SIGSEGV, и все может быстро испортиться. Просто избегайте всего беспорядка и позвольте SIGSEGV завершить вашу программу.)

  • Как вы обрабатываете сигналы, сложно.Если в вашем приложении есть основной цикл (например, select или poll), то обработчик сигнала может просто установить флаг или записать байт в специальный канал, чтобы подать сигнал на выход из основного цикла.Вы также можете использовать siglongjmp, чтобы выпрыгнуть из обработчика сигнала, но это ОЧЕНЬ сложно, чтобы получить правильную информацию, и обычно это не то, что вам нужно.

Трудно что-то рекомендовать, не зная какВаше приложение структурировано и что оно делает.

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

9 голосов
/ 11 сентября 2011

Вы устанавливаете обработчики сигналов для перехвата сигналов - однако в 99% случаев вы просто хотите выйти и позволить ОС Linux позаботиться об очистке - она ​​с радостью закроет все файлы, сокеты, свободную память и потоки завершения работы.

Поэтому, если вы не хотите что-то конкретно делать, например отправлять сообщение в сокеты, вам следует просто выйти из процесса и не пытаться перехватить сигнал.

7 голосов
/ 11 сентября 2011

Мне иногда нравится получать обратную трассировку на SIGSEGV, часть перехвата выглядит так:

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

void sig_handler(int);

int main() {
    signal(SIGSEGV, sig_handler);
    int *p = NULL;
    return *p;
}

void sig_handler(int sig) {
    switch (sig) {
    case SIGSEGV:
        fprintf(stderr, "give out a backtrace or something...\n");
        abort();
    default:
        fprintf(stderr, "wasn't expecting that!\n");
        abort();
    }
}

Вы действительно хотите быть очень осторожными, обращаясь с этими вещами, например, убедитесь, что вы не можете вызвать другой сигнал.

...