Linux 进程的退出

目录

进程退出

退出场景

常见的退出方法

正常退出

异常退出

_exit()系统调用

exit()函数

_exit()和exit()的区别

return 


进程退出

退出场景

  1. 正常符合预期退出
  2. 正常不符合预期退出
  3. 异常退出(执行过程中异常奔溃, 还未执行完)

常见的退出方法

正常退出

  1. main函数返回 ( return )
  2. 调用 exit( int status )函数
  3. 使用 _exit( int status )系统调用接口

可以使用ench $? 来查看进程退出码

异常退出

  1. 向进程发送信号导致进程异常退出(如 Ctrl+c)
  2. 代码错误导致进程运行时奔溃异常退出

说明 : 第二种情况是代码错误导致异常终止没什么说的, 就是代码问题

第一种情况是 Unix / Linux 系统中的信号是系统响应某些状况而产生的事件,是进程间通信的一种方式。信号可以由一个进程发

送给另外进程,也可以由核发送给进程 .

信号处理程序

信号处理程序是进程在接收到信号后, 系统对信号的响应. 根据具体信号的涵义, 相应的默认信号处理程序会采取不同的信号处理方式:

  • 终止进程运行, 并且产生core dump (核心转储文件)(记录一些错误信息, 方便用户查看)
  • 终止进程运行
  • 忽略信号,进程继续执行 .
  • 暂停进程运行 .
  • 如果进程已被暂停,重新调度进程继续执行 .

前两种方式会导致进程异常退出. 实际上,大多数默认信号处理程序都会终止进程的运行。

在进程接收到信号后,如果进程已经绑定自定义的信号处理程序, 进程会在用户态执行自定义的信号处理程序. 如果没有绑定,内

核会执行默认信号程序终止进程运行,  导致进程异常退出 .

例如: kill()函数, 在Shell中执行kill 指令, 在终端用键盘发送信号, 如:Ctrl+c , 都是发送信号来终止进程

_exit()系统调用

void _exit (int status)

头文件 : unistd.h

参数 :status 定义了进程的终止状态,父进程通过wait() 来获取该值(wait() 函数, 用于进程等待, 下面说).

说明 :虽然status是int,占但是仅有低8位可以被父进程所用. 在下面小结进程等待中详细说

功能 :   直接使进程停止运行,清除其使用的内存空间,并销毁其在内核中的各种数据结构

exit()函数

void exit (int status)

头文件 : stdlib.h

参数status 与_exit中同理

exit() 底层封装了 _exit 系统调用, 在底层调用_exit之前,  还做了下面的工作

  • 执行用户通过 atexit 或 on_exit定义的清理函数。
  • 关闭所有打开的流,所有的缓存数据均被写入 (即刷新缓冲区)
  • 调用 _exit()

_exit()和exit()的区别

  • 最大的区别是 exit()函数在调用 _exit() 系统调用之前要检查文件的打开情况,把文件缓冲区中的内容写回文件 (即刷新缓冲
    区), 然后将控制权交给内核 . _exit() 则是执行后立即返回给内核,而exit()要先执行一些清除操作,
     
  • 调用_exit函数时,会关闭进程所有的文件描述符,清理内存以及其他一些内核清理函数,但不会刷新缓冲区, exit函数是在_exit函数之上的一个封装,其会调用_exit,并在调用之前先刷新缓冲区。
     
  • 补充: exit()函数在调用exit系统之前要检查文件的打开情况,把文件缓冲区的内容写回文件。由于Linux的标准函数库中,由于内存中都有一片缓冲区.  每次读文件时,会连续的读出若干条记录,这样在下次读文件时就可以直接从内存的缓冲区读取.  同样,每次写文件的时候也仅仅是写入内存的缓冲区,等满足了一定的条件(如达到了一定数量或遇到特定字符等),再将缓冲区中的内容一次性写入文件。这种技术大大增加了文件读写的速度,但也给编程代来了一点儿麻烦。比如有一些数据,认为已经写入了文件,实际上因为没有满足特定的条件,它们还只是保存在缓冲区内,这时用_exit()函数直接将进程关闭,缓冲区的数据就会丢失。因此,要想保证数据的完整性,就一定要使用exit()函数。

举栗子

#include<stdio.h>
#include<stdlib.h>
int main(){
    printf("hello world!");
    exit(0);
    return 0;
}

#include<stdio.h>
#include<unistd.h>
int main(){
    printf("hello world!");
    _exit(0);
}

可以看到, 并没有输出hello world! ,  这就_exit()没有刷新缓冲区, 导致在缓冲区的字符串没有打印到显示器进程就退出了, 造成数据丢失 .(注意hello world! 后面不能有\n, 因为\n会刷新输出缓冲区,  影响结果) 

return 

return是一种更常见的退出进程方法. 执行return n等同于执行exit(n), 因为main中 return n时, 系统会将main的返回值当做 exit()

的参数

发布了223 篇原创文章 · 获赞 639 · 访问量 12万+

猜你喜欢

转载自blog.csdn.net/qq_41071068/article/details/103302874
今日推荐