Подтвердить что ты не робот

Linux C ловит сигнал об улавливании для изящного завершения

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

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

4b9b3361

Ответ 1

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

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

Ответ 2

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

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

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

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

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

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

Ответ 3

Мне иногда нравится получать обратную трассировку на 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();
    }
}

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