避免执行某个函数atexit()的方法

避免执行某个函数的atexit的方法

问题

调用的一个外部函数中有atexit注册的函数,现因业务需求,不希望那个函数里通过atexit注册的函数被执行。

解决方法

在这里插入图片描述

代码实现

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h> 

void cleanup() {
    printf("clean up!\n");
}

void external_fun() {
    atexit(cleanup);
    printf("external function!\n");
}

void cal(int n){
    printf("print pid %d!\n", n);
}

int main() {
    atexit(cleanup);

    pid_t pid = fork();

    if(pid < 0) {
        perror("fork failed");
    }

    if (pid == 0) {
        cal(pid);
        external_fun();
        execl("/bin/ls", "ls", "/dev/null", (char *) NULL); // execl随便执行个什么,替换当前进程映像
        perror("execl failed");
        exit(EXIT_FAILURE);
    }
 
    if (pid > 0) {
        wait(NULL); //等待子进程执行结束
        cal(pid);
    }

    return 0;
}

执行结果

print pid 0!
external function!
/dev/null
print pid 1070702!
clean up!

可以看到,在子进程中的external_fun确实没有执行atexit注册的cleanup,且没有影响到parent进程的atexit(cleanup)

解释

执行execl()会替换当前进程的映像,包括:

  1. 代码段:存储程序的可执行代码。它包含了进程执行的指令。
  2. 数据段:包括全局变量和静态变量。这里存储了程序运行时需要的静态数据。
  3. 堆:动态分配的内存区域,用于存储程序在运行时通过 malloc、calloc、new 等函数分配的内存。
  4. 栈:用于存储函数调用时的局部变量、函数参数和返回地址。栈是先进后出(LIFO)的内存结构。
  5. 内存映射区域:包括程序的库文件(如共享库)、映射的文件等。这些区域可以通过 mmap 等系统调用映射到进程的地址空间。
  6. 文件描述符表:包含进程打开的文件和设备的句柄。

通过 atexit 注册的函数会被存储在一个特定的数据结构中,这个结构是数据段的一部分。它允许操作系统在进程终止时按注册顺序调用这些函数,一般用于执行清理工作,如释放资源或关闭文件。

因此在程序结束前,通过execl随便执行一个新进程替换当前的程序映像,便不会执行到atexit注册的函数。

为了避免替换进程映像后影响到当前进程的资源释放,通过fork子进程的方式,将我们不希望执行atexit的函数放到子进程中执行,在它之后要执行的函数仍在parent进程中执行,并等待子进程执行结束。于是,我们就只需要关心子进程里的那个函数的资源释放问题了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值