linux进程退出之exit与_exit

linux进程退出之exit与_exit

  • _exit
  • exit
    • 流程
    • 清理函数
      • `atexit()`函数:
      • `on_exit()`函数:

_exit

/* Terminate program execution with the low-order 8 bits of STATUS.  */
/** status参数定义了进程的终止状态,父进程可以通过wait()来获取该状态值。* 虽然status是int型,但是仅有低8位可以被父进程所用。*/
extern void _exit (int __status) __attribute__ ((__noreturn__));

功能
调用_exit()函数会使程序立即退出,不会进行任何清理操作。用户调用_exit函数,本质上是调用exit_group系统调用。

exit

/* Call all functions registered with `atexit' and `on_exit',in the reverse of the order in which they were registered,perform stdio cleanup, and terminate program execution with STATUS.  */
/*1. exit()函数的最后也会调用_exit()函数,但是exit在调用_exit之前,还做了其他工作:2.   1)执行用户通过调用atexit函数或on_exit定义的清理函数。3.   2)关闭所有打开的流(stream),所有缓冲的数据均被写入(flush),通过tmpfile创建的临时文件都会被删除。4.   3)调用_exit。*/
extern void exit (int __status) __THROW __attribute__ ((__noreturn__));

exit与_exit区别

流程

  1. 首先是exit函数会执行用户注册的清理函数。用户可以通过调用atexit()函数或on_exit()函数来定义清理函数。这些清理函数在调用return或调用exit时会被执行。执行顺序与函数注册的顺序相反。当进程收到致命信号而退出时,注册的清理函数不会被执行;当进程调用_exit退出时,注册的清理函数不会被执行;当执行到某个清理函数时,若收到致命信号或清理函数调用了_exit()函数,那么该清理函数不会返回,从而导致排在后面的需要执行的清理函数都会被丢弃

  2. 其次是exit函数会冲刷(flush)标准I/O库的缓冲并关闭流。
    glibc提供的很多与I/O相关的函数都提供了缓冲区,用于缓存大块数据。缓冲有三种方式:无缓冲(_IONBF)、行缓冲(_IOLBF)和全缓冲(_IOFBF)。

  • 无缓冲:就是没有缓冲区,每次调用stdio库函数都会立刻调用read/write系统调用。
  • 行缓冲:对于输出流,收到换行符之前,一律缓冲数据,除非缓冲区满了。对于输入流,每次读取一行数据。
  • 全缓冲:就是缓冲区满之前,不会调用read/write系统调用来进行读写操作。

对于后两种缓冲,可能会出现这种情况:进程退出时,缓冲区里面可能还有未冲刷的数据。如果不冲刷缓冲区,缓冲区的数据就会丢失。比如行缓冲迟迟没有等到换行符,又或者全缓冲没有等到缓冲区满。尤其是后者,很容易出现,因为glibc的缓冲区默认是8192字节。exit函数在关闭流之前,会冲刷缓冲区的数据,确保缓冲区里的数据不会丢失。

  1. 存在临时文件,exit函数会负责将临时文件删除。
  2. 调用_exit()函数。

清理函数

可以使用atexit()函数或on_exit()函数来注册清理函数,以在程序终止时执行一些特定的清理操作。

atexit()函数:

  • 原型:int atexit(void (*function)(void))
  • 作用:用于注册一个清理函数,该函数在程序正常终止时被调用。
  • 参数:function是一个指向无返回值的函数的指针,该函数没有参数。
  • 返回值:成功注册清理函数时返回0,失败时返回非零值。

以下是使用atexit()函数注册清理函数的示例:

#include <stdio.h>
#include <stdlib.h>void cleanup1()
{printf("Cleaning up...1\n");
}void cleanup2()
{printf("Cleaning up...2\n");
}int main()
{printf("Main program starts.\n");// 注册清理函数atexit(cleanup1);atexit(cleanup2);printf("Main program ends.\n");exit(0);
}

运行结果:
在这里插入图片描述

在上述示例中,cleanup()函数被注册为清理函数。当程序正常终止时,清理函数会被自动调用。

on_exit()函数:

  • 原型:int on_exit(void (*function)(int status, void *arg), void *arg)
  • 作用:用于注册一个清理函数,该函数在程序终止时被调用,不论是正常终止还是异常终止
  • 参数:
    • function是一个指向接受两个参数的函数指针,第一个参数是终止状态码,第二个参数是可选的自定义参数。
    • arg是一个可选的自定义参数,会传递给清理函数。
  • 返回值:成功注册清理函数时返回0,失败时返回非零值。

以下是使用on_exit()函数注册清理函数的示例:

#include <stdio.h>
#include <stdlib.h>void cleanup1() {printf("Cleanup 1 called\n");
}void cleanup2(int status, void *arg) {printf("Cleanup 2 called with status: %d, arg: %p\n", status, arg);
}int main() {// 使用 on_exit 函数注册终止处理函数on_exit(cleanup1, NULL);on_exit(cleanup2, (void *)0x12345678);printf("Main function executing\n");// 这里可以添加一些其他逻辑// return是一种更常见的终止进程的方法。// 执行return(n)等同于执行exit(n),因为调用main()的运行时函数会将main的返回值当作exit的参数。return 0;
}

运行结果:
在这里插入图片描述

在上述示例中,cleanup()函数被注册为清理函数,并且不接受自定义参数。当程序终止时,清理函数会被自动调用,并传递终止状态码作为参数。

推荐使用atexit,因为atexit是c标准函数,不同系统都会支持。而on_exit可能会在某些平台下无法支持,此函数来自 SunOS 4,但也存在于 libc4、libc5 和 glibc 中。它不再出现在 Solaris (SunOS 5) 中。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/588671.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

前端学习<四>JavaScript基础——01-编程语言和JavaScript简介

计算机语言 概念 计算机语言&#xff1a;人与计算机之间通信的语言。它是人与计算机之间传递信息的媒介&#xff0c;它通过特定的语法规则和语义约定&#xff0c;将人类可理解的指令转化为计算机可以执行的机器指令。 计算机程序&#xff1a;就是计算机所执行的一系列的指令…

【2024系统架构设计】案例分析- 5 Web应用

目录 一 基础知识 二 真题 一 基础知识 1 Web应用技术分类 大型网站系统架构的演化:高性能、高可用、可维护、应变、安全。 从架构来看:MVC,MVP,MVVM,REST,Webservice,微服务。

Pytorch for training1——read data/image

blog torch.utils.data.Dataset create dataset with class torch.utils.data.Dataset automaticly import torch from torch.utils.data import Datasetclass MyDataset(Dataset):def __init__(self, data):self.data datadef __getitem__(self, index):# 根据索引获取样本…

排序算法-归并排序

Leetcode链接&#xff1a;. - 力扣&#xff08;LeetCode&#xff09; 归并&#xff1a;将原始数组划分为若干个子数组&#xff0c;然后将这些子数组分别排序&#xff0c;最后再将已排序的子数组合并成一个有序的数组。是一种分治思想 思路&#xff1a; 1.分 2.治 3.怎么治 …

Codeforces TypeDB Forces 2023 C. Remove the Bracket【上下界DP】

C. Remove the Bracket 题意 给定一个长度为 n n n 的整数数组 a a a 和一个非负整数 s s s 要求 ∀ i ∈ [ 2 , n − 1 ] , 选定两个整数 x i , y i &#xff0c;满足 x i y i s 且 ( x i − s ) ( y i − s ) ≥ 0 \forall i \in [2,n - 1],选定两个整数 x_i, y_i&am…

恶意勒索Word文档模版注入分析

文章目录 前言1、工具&#xff1a;2、IOC样本&#xff1a;3、样本提取4、恶意文档分析参考手册 恶意的文档执行流程一、使用 OLEDUMP 和 OLEVBA 分析Word 文档1、OlEDUMP2、OLEVBA 二、使用 Detect-It Easy 识别文件类型-简单三、使用 7-zip 探索 OOXML 文档并查找模板注入四、…

程序员为什么要一直写 bug ?

程序员并不是故意写bug的&#xff0c;bug的产生通常是由多种因素导致的&#xff0c;例如&#xff1a; 需求理解不足&#xff1a;如果程序员没有完全理解项目的需求或者功能要求&#xff0c;可能会在编程过程中遗漏一些重要的细节&#xff0c;导致bug的产生。编程经验不足&…

Three.js真实相机模拟

有没有想过如何在 3D Web 应用程序中模拟物理相机&#xff1f; 在这篇博文中&#xff0c;我将向你展示如何使用 Three.js和 OpenCV 来完成此操作。 我们将从模拟针孔相机模型开始&#xff0c;然后添加真实的镜头畸变。 具体来说&#xff0c;我们将仔细研究 OpenCV 的两个失真模…

是谁?写的Java神作一出版就获Jolt图书大奖【抽奖赠书】

送书活动 1️⃣参与方式&#xff1a;点此参与抽书抽奖 2️⃣获奖方式&#xff1a;小程序随机 抽5位&#xff0c;每位小伙伴一本《Effective Java中文2024版》 3️⃣活动时间&#xff1a;截止到 2024-4-6 12:01:00 注&#xff1a;所有抽奖活动都是全国范围免费包邮到家&#xff…

openldap(一):简介和安装

目录 1 OpenLDAP简介1.1 LDAP介绍1、什么LDAP2、为什么要使用LDAP3、LDAP 的特点4、LDAP常用关键字5、LDAP的objectClass6、LADP使用场景 1.2 OpenLDAP介绍1、什么OpenLDAP2、OpenLDAP特点3、OpenLDAP的组件 2 OpenLDAP安装3 简单使用3.1 创建用户1、创建ou2、创建Group 3、创建…

Oracle基础-PL/SQL编程 备份

1、PL/SQL简介 PL/SQL块结构 约定&#xff1a;为了方便&#xff0c;本文后面把PL/SQL简称PL。 PL程序都是以块&#xff08;BLOCK&#xff09;为基本单位&#xff0c;整个PL块分三部分&#xff1a;声明部分&#xff08;使用DECLARE开头&#xff09;、执行部分(以BEGIN开头)和异…

springboot之RESTful接口与Swagger

一、RESTful GET获取资源、POST新建资源、PUT更新资源、DELETE删除资源。 RESTful两大特性 1、安全性&#xff1a;GET请求不会引起资源本身改变。 2、幂等性&#xff1a;对一个接口请求和多次请求返回的资源应该一致。 2xx&#xff1a;成功 4xx&#xff1a;客户端错误。 …