1、相关概念.
1.程序、进程、线程
程序并不能单独运行,只有将程序装载到内存中,系统为它分配资源才能运行,而这种执行的程序就称之为进程。程序和进程的区别就在于:程序是指令的集合,它是进程运行的静态描述文本;进程是程序的一次执行活动,属于动态概念。允许多个程序同时加载到内存中,在操作系统的调度下,可以实现并发地执行。这是这样的设计,进程的出现让每个用户感觉到自己独享CPU.
线程是进程的一个实体, 是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源。(这是一般性理解,然后在内核中,线程和进程的概念比较模糊,有时候甚至是当作同义词,通常把进程的和体系结构相关部分称为线程,这点要注意)
2.进程和线程的差别
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个进程死掉就等于整个线程死掉,所以多进程的程序要比多线程的程序 健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程.
3.多任务的真相
在多处理器系统中,真正并行运行的进程数目不超过物理CPU的数目.内核跟处理器建立了多任务的错觉,通过在很短的时间间隔在系统运行的各个程序之间不停切换而达到的目的,由于切换时间极短,用户无法注意到短时间内的停滞,从感官上觉得计算机能够同时处理多任务,本质上是欺骗了你的眼睛.
4.进程优先级
硬实时进程-任务的处理有严格的时间限制,必须在给定时间内执行,Linux版本不支持硬实时处理。软实时进程-硬实时进程的弱化形式。
5.抢占式多任务处理(preemptive multitasking)
各个进程都分配到一定时间段可以执行,时间段到期后,内核从进程收回控制权,让另一个进程运行,而不考虑前一进程所执行的任务,被抢占的进程执行环境会被保存起来,待恢复执行时,其环境可以完全恢复。时间片的长度会根据进程的重要性的不同而变化,而这个是由调度器策略来完成的。
6.进程生命周期
。运行:进程正在运行。
。等待:进程能够运行但是没有得到许可,调度器可以在下一次任务切换的时候选择该进程;
。睡眠:该进程在睡眠无法运行,因为在等待一个外部事件来唤醒,调度器无法在下一次任务切换时候选择该进程。
7.抢占多任务处理
。两种进程状态选项:用户态 - 核心态,建立封闭的隔离罩,防止各个进程不干扰系统其他组成部分;
。进程通常处理用户态,只能访问自身数据,而无法干扰系统中其他的进程,进程不会感受到自身之外的其他程序存在,好像只有自己一个程序独享整个系统一样.
。进程可以通过System call或者中断的方式切换到核心态访问系统资源。但中断切换到核心态时不可访问用户虚拟内存空间.
。普通进程可以被其他进程抢占。
。如果系统处理核心态并正在处理系统调用,那么其他进程无法抢占夺取其CPU,中断除外,中断具有最高优先级,可以抢占用户态或者核心态进程CPU (特别重要的内核操作也可以停掉中断).
8.进程的表示
。进程的所有算法都围绕 task_struct 的数据结构而建立,该结构包含很多成员,将进程与各个内核子系统联系起来.
./include/linux/sched.h:1295
。task_struct 资源限制成员:
rlim_cur :进程当前资源限制-软限制;
rlim_max:进程允许最大资源限制-硬限制;
。此图表跟体系结构相关.
命名空间(namespace)
。命名空间提供了虚拟化实现的轻量级实现,提供一种资源隔离方案,PID,IPC,Network等系统资源不再是全局性的,而是属于某个特定下的namespace,每个特定namespace下的资源对于其他namespace下的资源都是透明不可见的。因此在OS层面看就会出现多个相同pid的进程,由于分属不同的namespce,这些相同pid的进程不会冲突,而在用户层面只能看到属于自己的namespace下的资源,使用ps命令只能显示自己namespace下的进程,这样每个namespace看上去就想一个单独的OS,相当于,一个内核运行了多个OS,也就是虚拟化的基本实现.
。namespace 提供了放置一组进程的容器,各个容器彼此隔离,隔离可以使得各个容器内的成员之间毫无关系,但也运行容器进行一定的共享.本质上namespace建立了系统层面的不同视图.namespace还可以组织为层级关系.
。namespace 的创建可以通过两种系统调用创建:
1. fork 或者clone 创建新进程时,有特定选项可以控制.
2. unshare 系统调用可以将进程从当前命名空间分离.
3. 各个进程和命名空间之间的联系.
。重要的数据结构
UTS (Unix timesharing system)命名空间包含运行内核的名称、版本、体系结构等信息;
IPC 命名空间保存所有与ipc通讯的相关信息;
MNT 命名空间同文件系统相关的视图;
PID 命名空间包含有关pid的信息;
NET 命名空间包含所有network相关的信息.
。每个进程都关联到自身的namespace :
。用户命名空间创建使用fork或者clone实现,最终使用do_fork 系统调用实现,代码流程如下:
流程简图:
进程ID.
。相关概念:
PID:这是 Linux 中在其命名空间中唯一标识进程而分配给它的一个号码,称进程ID号,简称PID。在使用 fork 或 clone 系统调用时产生的进程均会由内核分配一个新的唯一的PID值。
TGID:在一个进程中,如果以CLONE_THREAD标志来调用clone建立的进程就是该进程的一个线程,它们处于一个线程组,该线程组的ID叫做TGID。处于相同的线程组中的所有进程都有相同的TGID;线程组组长的TGID与其PID相同;一个进程没有使用线程,则其TGID与PID也相同。
PGID:另外,独立的进程可以组成进程组(使用setpgrp系统调用),进程组可以简化向所有组内进程发送信号的操作,例如用管道连接的进程处在同一进程组内。进程组ID叫做PGID,进程组内的所有进程都有相同的PGID,等于该组组长的PID。
SID:几个进程组可以合并成一个会话组(使用setsid系统调用),可以用于终端程序设计。会话组中所有进程都有相同的SID。
全局ID:在内核本身和初始命名空间中唯一的ID,在系统启动期间开始的 init 进程即属于该初始命名空间。系统中每个进程都对应了该命名空间的一个PID,叫全局ID,保证在整个系统中唯一。
局部ID:对于属于某个特定的命名空间,它在其命名空间内分配的ID为局部ID,该ID也可以出现在其他的命名空间中。
。数据结构:
ID 的类型 PIDTYPE_MAX 表示 ID 类型数目。之所以不包括线程组ID,是因为内核中已经有指向到线程组的 task_struct 指针 group_leader,线程组 ID 就是 group_leader 的PID.
tasks是一个数组,每个数组项都是一个散列表头对应一个ID类型,所有共享给同一个给定PID的task_struct实例都通过该列表链接起来.
nr表示pid的值.
假如现在有三个进程A、B、C为同一个进程组,进程组长为A,数据结构关系图:
详解:http://www.cnblogs.com/hazir/p/linux_kernel_pid.html
进程关系.
。如果进程A分支形成进程B,进程A称为进程B的父进程,而进程B则是子进程;
。如果进程B再次分支形成进程C,那么进程A和进程C直接称为祖孙关系;
。如果进程A分支n次形成n个进程B1,B2..Bn,那么各个进程直接的关系称为兄弟进程.
内核线程.
内核线程数直接由内核本身启动的进程(如开头所述,Linux内核中,进程和线程概念比较模糊,通常是同义词).
...