Bootstrap

Linux:进程终止


return和exit的数据就是进程的退出码
一个程序运行起来是完成一个任务,只能通过退出码来表示当前进程任务处理的结果

进程常见退出方法:

  1. main函数return,在其它函数中return只能退出该函数
  2. ctrl+c:退出前台进程
  3. exit和_exit函数,在其它函数中调用程序就可以直接退出了

return和exit都是给进程一个返回值

三种退出场景

  • 任务完美完成,正常退出
  • 任务没有完成,正常退出
  • 异常退出
  • 正常退出一定是设置了退出码之后正常结束的

在这里插入图片描述

僵尸进程是退出,但是资源没有完全被释放,是为了保存退出原因(保存在PCB中)

exit和_exit函数的区别

  • exit是库函数,谁调用谁退出
    void exit (int ststus)
    status:进程退出的状态码
  • _exit是系统调用函数,谁调用谁退出
    void _exit (int status)
    status:进程退出的状态码
  • exit函数的内部封装了_exit函数,exit函数在退出进程的时候比_exit函数多做两件事
    1.刷新缓冲区(换行有刷新缓冲区的功能)
    2.执行用户自定义的清理函数

区别1 冲刷缓冲区

缓冲区:其实就是内存中临时存储数据的一块空间,这样做的目的是为了减少与物理内存交互的次数

在这里插入图片描述

  • 现象:一秒后hello才显示到屏幕上
  • 实质:打印hello并不是直接在屏幕上输出,是先缓存在内存中,然后再在缓冲区中将其内容冲刷出来;

加不加 \n 有一个本质区别:它是否刷新了缓冲区,

  • 也就是说将hello放在某个内存中,不加 \n 就没有主动刷新这个缓冲区到屏幕上去,在当前程序结束后才放入缓冲区刷新至屏幕

再次深入理解缓冲区:

库函数的代码实现是在C运行时库中,系统调用函数的代码实现是在内核当中,上面所说的缓冲区是在C运行时库中;


例如:

  • printf是一个库函数,调用printf后就把hello放入C运行时库定义的一个缓冲区(缓冲区是一块内存)中;
  • 加\n就主动刷新这块内存,将内存中内容输出到屏幕上,不加\n就要依赖别的刷新手段(程序结束刷新)

exit函数是靠 _exit函数实现的

在这里插入图片描述
现象:

  • 代码运行到exit(1)后结束,屏幕只显示hello,如果换成 _exit,则不会打印hello;

原因:

  • 系统调用函数比C库函数更底层
  • exit是一个库函数(终止一个进程),缓冲区也在C运行时库中;所以该库函数在实现时会刷新缓冲区,所以可以看到hello;
  • _exit函数是系统调用函数,并不知道C运行时库,直接结束进程并且也不刷新缓冲区,不打印hello

结论:exit会比_exit多做一件事,那就是刷新缓冲区

区别2 执行用户自定义的清理函数

先了解另一个知识点:
回调函数:

int atexit (void (*function) (void))

  • 参数:是函数指针类型,用来接收一个函数的地址,接收函数的返回值是void,参数也是void

在这里插入图片描述现象:先打印2,再打印1
原因:

  • atexit函数是注册 了一个函数mycallback(mycallback函数就是回调函数);
  • 当main函数结束后才会调用刚注册的mycallback函数

回调函数功能:

  • 先注册回调函数:调用atexit函数
  • 再调用回调函数:调用mycallback函数

atexit函数是清理函数,本质是回调函数

3.刷新缓存区的办法:

  1. main函数return返回之后
  2. fflush:强制刷新
  3. \n
  4. exit函数
;