有OS时,进程从启动到正常终止的全过程(进程环境)【linux】(zg)
有OS时,进程从启动到正常终止的全过程
我们来看上面的图,描述的非常清楚。这里的内核指的是linux内核
首先通过exec系统函数来运行,exec函数也被称为加载器,加载器就是用来加载运行程序的,会到硬盘上去把程序代码拷贝到内存上让PC(程序计数器)指向第一条指令,CPU从第一条指令开始寻址运行然后整个程序就被运行起来了,程序运行起来就是进程。
最开始运行的是启动代码,启动代码是整个C程序的开始代码,所以CPU执行的第一条指令一定是启动代码的第一条指令,指令代码去调用main函数,main函数调用我们其他自己写的子函数,在程序中的任何一个位置,无论是main函数还是子函数调用_exit 函数,就是直接退出返回到内核,调用—_exit是正常终止返回到内核。调用_exit函数不会返回。_exit函数的作用是终止当前进程,当前进程被终止也就没有返回的必要了。我们也可以通过main函数调用return来正常终止,return的作用就是返回调用的上一级,main函数调用的上一级就是启动代码,所以说main函数是启动代码的子函数,所以main函数调用return返回到启动代码,启动代码调用exit函数继续返回。当然我们说过我们也可以在程序的任何位置调用exit函数来进行正常终止进程,调用exit函数不会有任何的返回值,因为调用exit的目的始终进程,进程被终止也就没有返回值,调用exit函数最终还是调用_exit 不过exit做了额外的事情之后才去返回内核,例如调用进程终止处理函数来做扫尾处理,进程终止函数是我们调用atexit函数来登记的,使用exit函数进行退出的时候会调用终止处理函数。调用exit函数之后会关闭标准io。关闭标准io的时候向下连带就会把文件io关闭,因为标准io是基于文件io来工作的。并且刷新标准io的缓冲区,刷新之后把数据输出,然后调用_exit返回到操作系统内核,最终所有的都是调用_exit 返回到内核。
调用exit、return正常终止时,会刷新标准io的缓存
标准输出(printf)的库缓存就是行缓冲的,在缓存中积压的数据,直到出现以下情况时才会刷新输出,否则就一直挤压着:
①遇到\n时就刷新输出,\n表示这是一行,就好比句号表示一句话一样。
②库缓存中数据满了,也会自动刷新输出,这就好比盆里的水满了溢出一样。不过一般来说,数据不可能多到能够把缓存装满的。
③调用标准fflush函数,主动刷新数据
④调用fclose关闭标准输出时,会自动调用fflush刷新数据
为什么调用exit正常终止时,会刷新标准io的缓存呢?
因为exit会调用fclose关闭所有的标准io,关闭时会自动调用fflush来刷新数据调用文件io把数据输出。如果进程时异常终止的话,是不会刷新缓存区的,因为异常退出时,跟exit函数无关。