Linux进程和线程的基础与管理
一.的基本概念
程序是为了完成某种任务而设计的软件,比如vi是程序。什么是进程呢? 进程就是运行中的程序。一个运行着程序,可能有多个进程。比如Web服务器是Apache服务器,当管理员启动服务后,可能会有好多人来访问,也就是说许多用户同时请求httpd,Apache服务器将会创建多个httpd进程来对其进行服务。
首先我们看看进程的定义。进程是一个具有独立功能的程序关于某个数据集合的一次可以并发执行的运行活动,是处于活动状态的计算机程序。进程作为构成系统的基本细胞,不仅是系统内部独立运行的实体,而且是独立竞争资源的基本实体。了解进程的本质,对于理解、描述和设计操作系统有着极为重要的意义。了解进程的活动、状态,也有利于编制复杂程序。
二.进程的属性
进程的定义:一个进程是一个程序的一次执行的过程;程序是静态的,它是一些保存在磁盘上的可执行的代码和数据集合;进程是一个动态的概念,它是系统的基本的调度单位。
一个进程由如下元素组成:
- 程序读取的上下文,它表示程序读取执行的状态。
- 程序当前执行的目录。
- 程序服务的文件和目录。
- 程序访问的权限。
- 内存和其他分配给进程的系统资源。
Linux进程中最知名的属性就是它的进程号(Process Idenity Number,PID)和它的父进程号(Parent Process ID,PPID)。PID、PPID都是非零正整数。一个PID唯一地标识一个进程。一个进程创建新进程称为创建了子进程(Child Process)。相反地,创建子进程的进程称为父进程。所有进程追溯其祖先最终都会落到进号为1的进程身上,这个进程叫做init进程,是内核自举后第一个启动的进程。init进程扮演终结父进程的角色。因为init进程永远不会终止,所以系统总是可以确信它的存在,并在必要的时候以它为参照。如果某个进程它在衍生出来的全部子进程结束之前被终止,就会出现必须以init为参照的情况。此时那些失去了父进程的子进程就都会以init作为它们的父进程。如果执行一下ps-af命令,可以列出许多父进程ID为1的进程来。Linux提供了一条pstree命令,允许用户查看系统内正在运行的各个进程之间的继承关系。直接在命令行中输入pstree即可,程序会以树状结构方式列出系统中正在运行的各进程之间的继承关系。
三.理解Linux下进程的结构
Linux中一个进程在内存里有三部分数据,就是“数据段”、“堆栈段”、“代码段”。基于I386兼容的中央处理器,都有上述三种段寄存器,以方便操作系统的运行,如下图所示。
代码段是存放了程序代码的数据,假如机器中有数个进程运行相同的一个程序,那么它们就可以使用同一个代码段。而数据段则存放程序的全局变量、常数及动态数据分配的数据空间。堆栈段存放的就是子进程的返回地址、子程序的参数及程序的局部变量。堆栈段包含在进程控制块PCB(Process Control Block)中。PCB处于进程核心堆栈的底部,不需要额外分配空间。
四.进程状态
现在我们来看看,进程在生存周期中的各种状态及状态的转换。下面是Linux系统的进程状态模型的各种状态。
- 用户状态:进程在用户状态下运行的状态。
- 内核状态:进程在内核状态下运行的状态。
- 内存中就绪:进程没有执行,但处于就绪状态,只要内核调度它,就可以执行。
- 内存中睡眠:进程正在睡眠并且进程存储在内存中,没有被交换到SWAP设备。
- 就绪且换出:进程处于就绪状态,但是必须把它换入内存,内核才能再次调度它运行。
- 睡眠且换出:进程正在睡眠,且被换出内存。
- 被抢先:进程从内核状态返回用户状态时,内核抢先于它做了上下文切换,调度了另一个进程。原先这个进程就处于被抢先状态。
- 僵死状态(zombie):进程调用exit结束,进程不再存在,但在进程表项中仍有记录,该记录可由父进程收集。
现在我们从进程的创建到退出来看看进程的状态转化。需要说明的是,进程在它的生命周期里并不一定要经历所有状态。
五.Linux进程的创建
fork函数在Linux下产生新的进程的系统调用,这个函数名是英文中“分叉”的意思。为什么取这个名字呢? 因为一个进程在运行中,如果使用了fork,就产生了另一个进程,于是进程就“分叉”了,所以这个名字取得很形象。fork的语法如下所示: