基本定义
Process is a program in execution. 执行中的程序
-It associates with all the files opened by that process. 文件
-It attaches to all the memory that is allocated for it. 内存
-It contains every accounting information, 统计信息 e.g. running time, current memory usage, who owns the process,etc.
创建进程
fork() : 复制生成了一个子进程,子进程从调用fork的地方开始执行
复制了什么?
复制了 User space memory 中的所有内容,包括本地变量,全局变量,动态分配变量,代码和常量。
Kernel Space 中 只复制了文件数组,其他的比如PID,Running time,Children,Parent都不同。
fork() 方法的返回值不同,父进程返回子进程的PID,子进程返回0。
结果:
由于文件数组相同(包括标准输出,输入和错误输出),子进程与父进程打印的内容出现在同一个窗口。
父进程和子进程的执行顺序是不确定的,由系统的scheduler决定。
子进程的使用
exec*() 有6个成员函数
在User space上,所有本地变量和动态分配变量(栈和堆)被清空,代码变成新的代码,常量相应地改变,全局变量根据新代码进行设置。
在kernel space上,重置了 register ,比如 program counter。其他基本保留着,比如PID,Parent等。(文件数组呢?标准输出,输入,错误输出还是不变的,其他的应该也重置了(待确定))
结果:
一旦子进程执行了exec*(),不会再返回之前的代码(不同于普通的函数调用)。
子进程与父进程的协调
exit() :由子进程调用,表明运行结束。
在User space中,所有东西都会被清除。
在Kernel space中,分配的内存会被回收,所有相关文件都会关闭,但是保留PID还有退出状态(exit status),成为了zombie。
最后,kernel会发出SIGCHLD信号给父进程。
wait() : 由父进程调用,用于等待子进程运行结束 termination
kernel会为父进程注册一个signal handling routine用于将来处理SIGCHLD信号
如果父进程的子进程还未执行结束,父进程就会被挂起,直到收到了SIGCHLD,signal handling routine被触发,将子进程的zombie处理干净(彻底从kernel space中清除),然后wait()会返回子进程的PID。
如果父进程没有fork过任何子进程或者子进程早已运行结束,上述的清理流程会立刻执行。
waitpid() : 与wait()的区别在于,它能够指定某一个子进程的PID,并且可以侦测子进程的其他状态改变(而不仅仅是termination)
调用wait()的意义
系统资源利用:Linux中PID是有限的,zombie进程会占据一个PID,如果zombie一直产生但没有被处理,那么PID将可能被耗尽,系统无法创建新进程。
经典的可以造成死机的代码片段
int main(){
while(fork());
return 0;
}
关于re-parent:
Linux中, init进程会成为所有的“孤儿”进程的后妈。这个过程叫做re-parenting.
注意: 新的Linux kernels 可能不再选择init进程而是 祖父进程, user-level init进程等。
问题:zombie存在的意义?
答:确保无论父进程调用wait()的时间是在子进程结束之前还是之后,父进程都能够获取子进程结束的一些信息(比如 是否非正常退出?)。 参考:http://stackoverflow.com/questions/16416793/why-is-a-zombie-process-necessary
问题: 如果zombie进程的父进程忘记了wait,怎么清除zombie ?
答: 杀死那个父进程,那么这个父进程的所有子进程都会reparent,通常是init进程会成为他们的新父进程,接着init进程会wait它们,最后成功清除zombie。 参考: http://stackoverflow.com/questions/16944886/how-to-kill-zombie-process
问题:哪个process是系统的第一个进程?
答: init进程。
进程的生命周期
eady:指一个进程处于可以run但是还没run的状态,也可以理解为 runnable状态。
什么时候进程会处于ready状态? 1. 刚刚被fork出来 2. CPU context-switch到另外的进程 3. 刚从Blocked/Waiting状态返回
Running:进程获得了CPU,并且正在运行。
Blocked/Waiting : 显式地或者隐式地等待某些事情发生, 比如 在读取文件,父进程调用wait() 等。
有interruptable和un-interruptable两种类型,顾名思义,后一种类型的blocked状态是无法打断的,通常是一些特殊的API在驱动程序driver被滥用,导致电脑的卡顿现象。
问题:有没有什么办法打断un-interruptable blocked状态?
答:没有!除非关机,重启~
后台进程与前台进程
当在shell执行一个程序时,新建的进程默认是前台进程。前台进程继承了父进程(shell进程)的所有文件也包括了标准输入输出和错误输出,因此用户可以通过标准输入输出和新进程进行交互。
但是,当新进程收到了SIGTSTP信号被挂起时,或者运行程序时使用&指令,进程都会变成后台进程,此时,标准输入就不再可用。
注意:当进程因为SIGTSTP信号被挂起,而后又收到SIGCONT继续执行时,它仍然是作为后台进程在运行。(更多关于信号的内容,参见 https://my.oschina.net/Bruce370/blog/885260)
在shell调用fg指令,可以将后台进程带到前台。