在C中退出之前使用指针的全局数组进行清理



我有一个小程序,其中包含一个需要malloc:的变量

char **v;
v = (char**)malloc(sizeof(char *) * MAX_EVENTS);
for (int i = 0; i < MAX_EVENTS; i++)
v[i] = (char *)malloc(MAX_NAME_SIZE);

为了让Valgrind满意,避免任何内存泄漏,我为终止信号设置了处理程序。该处理程序将在退出之前释放该分配,并终止子进程。

static void term_handler() {
if (v != NULL) {
for (int i = 0; i < MAX_EVENTS; i++) {
if (v[i] != NULL)
free(v[i]);
}
free(v);
}
for (int i = 0; i < MAX_PROCS; i++)
if (children[i])
kill(children[i], SIGTERM);
exit(EXIT_SUCCESS);
}

为了从处理程序访问v,我将其作为全局变量。CCD_ 2是一个静态数组CCD_。

从处理程序访问这些分配的最干净的方法是什么?不建议使用全局变量,但内存泄漏和未正确终止的程序也不建议使用。我应该将指向分配的指针数组作为全局变量吗?还是应该避免处理意外信号?

信号处理程序很棘手,因为它们是异步调用的,因此在信号处理程序中只有一小部分函数调用是安全的。特别是,从信号处理程序中分配或释放内存是no(就像调用exit()一样!),所以不要这么做。

然而,如果你想确保内存被释放(*),你可以让你的信号处理程序"告诉"你的程序的主线程是时候退出了。然后,主线程可以脱离其事件循环,释放内存,并在退出之前进行任何其他正常的清理工作。

因此,问题变成了,信号处理程序如何安全地告诉主线程执行受控/优雅的退出?

如果主线程正在运行按固定时间表执行的事件循环(例如,每隔这么多毫秒),这可能很容易,只需声明一个全局变量(例如volatile bool pleaseQuitNow = false;,主线程在其事件循环的每次迭代中测试该变量,并让信号处理程序将该变量设置为不同的值。然后,主线程将在其下一次迭代中看到更改后的变量,并通过中断事件循环来做出响应。

另一方面,如果主线程的事件循环是基于事件的(例如,它在select()或poll()或类似的内部被阻止,并且调用在一段不确定的时间内不会返回),那么唤醒主线程的另一种方法是在程序启动时创建一个pipe()或socketpair(),并让主线程监视两个文件描述符中的一个,以了解读取就绪状态。然后,当信号处理程序运行时,它可以在另一个文件描述符上发送()一个字节,这将导致第一个文件描述符指示准备读取状态。主线程可以通过中断其事件循环并优雅地退出来响应读取就绪状态。

除了避免异步信号不安全的调用外,这样做的好处是只有一个关闭/清理路径来测试/调试/维护,而不是两个。

(*)当然,在任何现代操作系统上,内存都会被操作系统的进程清理例程释放;但是valgrind会抱怨内存泄漏,所以如果可能的话,最好手动释放内存,这样你就可以使用valgrind来找到"真正的"内存泄漏,而不必每次都对一堆误报进行分类。

最新更新