Правильная очистка в функции обработчика сигнала

Я сделал программу, которая использует функцию fork() для создания дочерних процессов. Его дочерние процессы выполняют некоторую работу, но я хочу, чтобы они завершались, когда получают сигнал SIGTERM от родительского процесса. Перед выходом я также хочу, чтобы они очистили выделенные мной массивы и отправили кое-что через FIFO родительскому процессу. Итак, у меня есть 2 сценария.

  1. Глобальные переменные для моих массивов, а также файловые дескрипторы для FIFO, а затем выход через функцию обработчика сигнала, например:

    /*global variables*/
    struct whatever ** test;
    int test_size;
    int fd_in, fd_out;
    
    /*handler*/
    void shutdown(int signo)
    {
          /*free memory for the arrays malloc'd through the program*/
          /*send message with the help of fd_out*/
          /*close fd_in and fd_out*/
          _exit(0);
    }
    
  2. Объявите глобальный флаг int, и когда дочерние процессы обнаружат, что флаг изменился, они очищают массивы, отправляют сообщения и завершают работу.

    /*global variables*/
    int exit_flag=0;
    
    /*handler*/
    void shutdown(int signo)
    {
          exit_flag=1;
    }
    
    /*child process*/
    int main()
    {
          /*declare fds and arrays*/
          /*use sigaction and set up handler*/
    
          while(!exit_flag)
          {
                 /*do stuff*/
          }
    
          /*free memory*/
          /*send message with the help of fd_out*/
          /*close fds*/
    }
    

Мой вопрос в том, какой сценарий приводит к хорошему кодированию/программированию? Они оба одинаковы или есть лучший и даже более правильный способ сделать это?


person Q_M    schedule 27.04.2017    source источник


Ответы (1)


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

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

Отдельно стоит отметить, что полезно иметь привычку объявлять глобальные флаги как volatile, чтобы гарантировать, что ваш компилятор не оптимизирует флаг до константы и не застрянет в бесконечном цикле.

volatile int exit_flag=0;
person Ryan Jones    schedule 27.04.2017