linux 进程基础(一)
计算机实际上所做的事情很简单,即通过对程序的调度执行,完成用户指定的一系列操作。这个过程我们可以这样在比喻,计算机是一个厨房,程序是一份菜谱、点菜的窗口就是一个输入,中间程序运行的过程就是计算机进行炒菜,而程序运行完成将结果呈现给用户的时候,就是程序运行的输出,即服务员将炒好的菜送到顾客面前。
那么进程和程序的区别又是什么呢?显然程序是存储在硬盘上的代码的集合,类似于上面比喻中的菜单,而进程就是运行的程序,其主要是运活动空间是内存。同一个程序可以被多次执行,进而形成多个进程,不同的进程可以拥有各自所需的运行资源,比如说IO读写接口、地址空间等,这也表明了进程之间是不能共享数据,但他们之间可以进行进程间的通信。结合实际情况,计算机中的进程可分为系统进程和用户进程,系统进程是系统程序产生的进程,用户进程是用户程序运行过程中产生的进程,可以这样理解,系统进程提供了用户进程运行时所必须的“物质支撑”,类似于前面比喻中的厨房这个角色。
针对进程其重点在于进程的创建、进程的消亡、进程的状态、进程间的通信、进程的调度。
一、进程的创建
实际上,当计算机开机的时候,内核(kernel)只建立了一个init进程。Linux kernel并不提供直接建立新进程的系统调用。剩下的所有进程都是init进程通过fork机制建立的。新的进程要通过老的进程复制自身得到,这就是fork。fork是一个系统调用。进程存活于内存中。每个进程都在内存中分配有属于自己的一片空间 (address space)。当进程fork的时候,Linux在内存中开辟出一片新的内存空间给新的进程,并将老的进程空间中的内容复制到新的空间中,此后两个进程同时运行。
老进程成为新进程的父进程(parent process),而相应的,新进程就是老的进程的子进程(child process)。一个进程除了有一个PID之外,还会有一个PPID(parent PID)来存储的父进程PID。如果我们循着PPID不断向上追溯的话,总会发现其源头是init进程。所以说,所有的进程也构成一个以init为根的树状结构。fork通常作为一个函数被调用。这个函数会有两次返回,将子进程的PID返回给父进程,0返回给子进程。实际上,子进程总可以查询自己的PPID来知道自己的父进程是谁,这样,一对父进程和子进程就可以随时查询对方。
二、进程的消亡
当子进程终结时,它会通知父进程,并清空自己所占据的内存,并在kernel里留下自己的退出信息(exit code,如果顺利运行,为0;如果有错误或异常状况,为>0的整数)。在这个信息里,会解释该进程为什么退出。父进程在得知子进程终结时,有责任对该子进程使用wait系统调用。这个wait函数能从kernel中取出子进程的退出信息,并清空该信息在kernel中所占据的空间。但是,如果父进程早于子进程终结,子进程就会成为一个孤儿(orphand)进程。孤儿进程会被过继给init进程,init进程也就成了该进程的父进程。init进程负责该子进程终结时调用wait函数。
当然,一个糟糕的程序也完全可能造成子进程的退出信息滞留在kernel中的状况(父进程不对子进程调用wait函数),这样的情况下,子进程成为僵尸(zombie)进程。当大量僵尸进程积累时,内存空间会被挤占。
本文出自 “简单新生活” 博客,谢绝转载!
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。