C 用信号清除动态分配的数据

C 用信号清除动态分配的数据,c,memory-management,malloc,signals,C,Memory Management,Malloc,Signals,使用signal时,使用C中的free()动态分配数据清理的正确方法是什么 有一个共享内存的例子,使用的解决方案是声明全局变量,但看起来不是很干净和安全 这是一个示例代码,其中动态分配了一个结构数组,但没有正确清理 #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> typedef struct { int val; } mystr

使用signal时,使用C中的
free()
动态分配数据清理的正确方法是什么

有一个共享内存的例子,使用的解决方案是声明全局变量,但看起来不是很干净和安全

这是一个示例代码,其中动态分配了一个结构数组,但没有正确清理

#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;
}
#包括
#包括
#包括
#包括
类型定义结构{
int-val;
}我的结构;
无效sigquit(内部sig){
信号(信号,信号);
printf(“儿童死亡”);
//清除内部的动态分配数据
//信号退出方法
//
//int i;
//对于(i=0;i

您将使用哪种方法来解决此问题?

让信号处理程序设置一个类型为
sig\u atomic\t
的变量。在您的常规代码中,定期检查要设置的变量,如果是,则完全关闭。如果需要,清洁关机必须设计成一个软件。根据POSIX,无论是
malloc()
还是
free()
还是任何其他高级内存分配函数都是信号安全的(
mmap()
和friends都是)。您无法在信号处理程序中安全地调用它们,因为从信号处理程序调用它们时不需要它们


典型的解决方法是在信号处理程序中设置一个标志,以清除内存。程序的主循环定期检查此标志,并在发现标志已设置时执行所需的操作。使用此变量的类型
sig_atomic\u t
,并将其声明为
volatile
,以获得最大的安全性。

与共享内存不同,大多数其他资源(如套接字和malloced内存)在程序退出之前不需要清理。这是因为在进程终止后,它们无论如何都会被清除


设置将在主循环中处理的标志对于其他信号来说是个好主意,但是对于
SIGQUIT
将不会像预期的那样工作,因为在调用信号处理程序后,您的进程将已经终止。

在实际代码中,子进程可能会使用
select
或其他类似机制产生事件循环。然后,一般的过程是让信号处理程序只设置一个标志。然后,事件循环将检测到这一点,并执行流程清理并在该点退出(在信号处理程序之外)。