2015-12-23 2 views
4

Каков правильный способ очистки с помощью free() динамических распределенных данных в C при использовании сигнала?Очистить динамически распределенные данные с сигналом

Here есть пример с общей памятью, а используемое решение - объявить глобальную переменную, но кажется не очень чистым и безопасным.

Это пример кода с массивом структуры динамически распределяемой не corretly очищено

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

typedef struct { 
    int val; 
} mystruct_t; 

void sigquit(int sig) { 
    signal(sig, SIG_IGN); 
    printf("Child killed\n"); 

    // Clear the dynamic allocated data inside 
    // the signal quit method 
    // 
    // int i; 
    // for (i = 0; i < n; i++) { 
    //  free(struct_a[i]); 
    // } 
    // free(struct_a); 

    exit(0); 
} 

int 
main() 
{ 
    int n = 10; 
    /* dynamic allocated array of structure */ 
    mystruct_t **struct_a = generatearray(n); 
    pid_t pid = fork(); 

    if (pid == 0) { 
     printf("Child process. My pid is %d and my parent's id is %d.\n", 
      getpid(), getppid()); 

     if (signal(SIGQUIT, sigquit) == SIG_ERR) { 
      printf("SIGINT install error\n"); 
      exit(1); 
     } 

     while(1); 
    } 
    else { 
     printf("Parent process. My pid is %d and my parent's id is %d.\n", 
      getpid(), pid); 

     sleep(1); 
     kill(pid, SIGQUIT); 
     sleep(5); 
    } 

    return 0; 
} 

Какой метод вы будете использовать, чтобы решить эту проблему?

+0

В реальном коде, вероятно, дочерний процесс будет иметь цикл событий, используя 'select' или какой-либо другой аналогичный механизм. Тогда общая процедура для обработчика сигнала просто устанавливает флаг. Затем цикл события обнаружит это и очистит процесс и выйдет в эту точку (вне обработчика сигнала). – kaylum

ответ

4

Согласно POSIX, ни malloc(), ни free(), ни какие-либо другие функции выделения памяти высокого уровня не являются безопасными (mmap() и их друзья). Вы не можете безопасно называть их в обработчике сигналов, так как они не требуют выживания, вызываемого из обработчика сигналов.

Типичное обходное решение - установить флаг в обработчике сигнала, чтобы память очищалась. Основной цикл вашей программы периодически проверяет этот флаг и выполняет требуемое действие при обнаружении флага. Для этой переменной используйте тип sig_atomic_t и объявите его как volatile для обеспечения максимальной безопасности.

2

Установите регулятор сигнала переменной типа sig_atomic_t. В вашем обычном коде периодически проверяйте, чтобы эта переменная была установлена, и, если это так, отключитесь. Чистое отключение, при необходимости, должно быть сконструировано в виде части программного обеспечения. В конце он не может быть «сшиван».

0

В отличие от общей памяти, большинство других ресурсов (например, сокетов и malloced memory) не требуют очистки перед выходом программы. Это происходит потому, что они очищаются в любом случае после завершения процесса.

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

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