1、进程和程序
linux
1.进程的基本概念缓存
所谓进程是由正文段用户数据段以及系统数据段共同组成的一个执行环境,是一个动态实体。网络
2.程序的基本概念数据结构
程序只是一个普通文件,是一个机器代码指令和数据的集合,这些指令和数据存储在磁盘上的一个可执行映像中,因此,程序是一个静态的实体。ide
3.进程的组成部分函数
(1)正文段:存放被执行的机器指令。这个段是只读的(因此,在这里不能写本身能修改的代码),它容许系统中正在运行的两个或多个进程之间可以共享这一代码。spa
(2)用户数据段:存放进程在执行时直接进行操做的全部数据,包括进程使用的所有变量在内。显然,这里包含的信息能够被改变。虽然进程之间能够共享正文段,可是每一个进程须要有它本身的专用用户数据段。操作系统
(3)系统数据段:该段有效地存放程序运行的环境。事实上,这正是程序和进程的区别所在。做为动态事物,进程是正文段、用户数据段和系统数据段的信息的交叉综合体,其中系统数据段是进程实体最重要的一部分,之因此说它有效地存放程序运行的环境,是由于这一部分存放有进程的控制信息。Linux为每一个进程创建了task_struct数据结构来容纳这些控制信息。.net
4.进程和程序总结线程
程序装入内存后就能够运行了:在指令指针寄存器的控制下,不断地将指令取至CPU运行。这些指令控制的对象不外乎各类存储器(内存、外存和各类CPU寄存器等),这些存储器中保存有待运行的指令和待处理的数据,固然,指令只有到CPU才能发挥其做用。
Linux是一个多任务操做系统,也就是说,能够有多个程序同时装入内存并运行,操做系统为每一个程序创建一个运行环境即建立进程,每一个进程拥有本身的虚拟地址空间,它们之间互不干扰,即便要相互做用(例如多个进程合做完成某个工做),也要经过内核提供的进程间通讯机制(IPC)
2、task_struct结构描述
1.Linux中的每一个进程由一个task_struct数据结构来描述,task_struct其实就是一般所说的“进程控制块”即PCB。task_struct容纳了一个进程的全部信息,是系统对进程进行控制的惟一手段,也是最有效的手段。
2.task_struct数据结构全部域以下:
*进程状态(State);
僵死状态:进程虽然已经终止,但因为某种缘由,父进程尚未执行wait()系统调用,终止进程的
信息也尚未回收。
*进程调度信息(Scheduling Information);
调度策略
只有root用户能经过sched_setscheduler()系统调用来改变调度策略。
*各类标识符(Identifiers);
*进程通讯有关信息(IPC,Inter_Process Communication);
Linux 支持多种不一样形式的通讯机制。它支持典型的UNIX通讯机制(IPC Mechanisms):信号、管道,也支持System V通讯机制:共享内存、信号量和消息队列。
*时间和定时器信息(Times and Timers);
一个进程从建立到终止叫作该进程的生存期(lifetime)。进程在其生存期内使用 CPU的时间,内核都要进行记录,以便进行统计、计费等有关操做。进程耗费CPU的时间由两部分组成:一是在用户模式(或称为用户态)下耗费的时间、一是在系统模式(或称为系统态)下耗费的时间。每一个时钟滴答,也就是每一个时钟中断,内核都要更新当前进程耗费CPU的时间信息。
创建了“时间”的概念,“定时”就是垂手可得的了,无非是判断系统时间是否到达某个时刻,而后执行相关的操做而已。Linux提供了许多种定时方式,用户能够灵活使用这些方式来为本身的程序定时。
*进程连接信息(Links);
程序建立的进程具备父/子关系。由于一个进程能建立几个子进程,而子进程之间有兄弟关系,在 task_struct结构中有几个域来表示这种关系。
在Linux系统中,除了初始化进程init,其余进程都有一个父进程或称为双亲进程。 能够经过 fork()或 clone()系统调用来建立子进程, 除了进程标识符(PID)等要的信息外,子进程的task_struct结构中的绝大部分的信息都是从父进程中拷贝,或说“克隆”过来的。系统有必要记录这种“亲属”关系,使进程之间的协做更加方便,例如父进程给子进程发送杀死(kill)信号、父子进程通讯等,就能够用这种关系很方便地实现。
*文件系统信息(File System);
进程能够打开或关闭文件,文件属于系统资源,Linux内核要对进程使用文件的状况进行记录。task_struct结构中有两个数据结构用于描述进程与文件相关的信息。其中,fs_struct中描述了两个 VFS索引节点,这两个索引节点叫作root和pwd,分别指向进程的可执行映像所对应的根目录和当前目录或工做目录。file_struct结构用来记录了进程打开的文件的描述符。
在文件系统中,每一个VFS索引节点惟一描述一个文件或目录,同时该节点也是向更低层的文件系统提供的统一的接口。
*虚拟内存信息(Virtual Memory);
*页面管理信息(page);
*对称多处理器(SMP)信息;
*和处理器相关的环境(上下文)信息(Processor Specific Context);
*其余信息。
3、task_struct 结构在内存中的存放
内核栈:每一个进程都有本身的内核栈。当进程从用户态进入内核态时,CPU就自动地设置该进程的内核栈。
从这个结构能够看出,内核栈占8KB 的内存区。实际上,进程的task_struct结构所占的内存是由内核动态分配的,更确切地说,内核根本不给task_struct分配内存,而仅仅给内核栈分配8KB的内存,并把其中的一部分给task_struct使用。
task_struct结构大约占1K字节左右,其具体数字与内核版本有关,由于不一样的版本其域稍有不一样。所以,内核栈的大小不能超过7KB,不然,内核栈会覆盖task_struct结构,从而致使内核崩溃。不过,7KB大小对内核栈已足够。
把task_struct结构与内核栈放在一块儿具备如下好处:
*内核能够方便而快速地找到这个结构,用伪代码描述以下:
task_struct = (struct task_struct *) STACK_POINTER & 0xffffe000(8K)
*避免在建立进程时动态分配额外的内存。
*task_struct 结构的起始地址老是开始于页大小(PAGE_SIZE)的边界。
4、进程的组织方式
1.哈希表
哈希表是进行快速查找的一种有效的组织方式。Linux在进程中引入的哈希表叫作pidhash,在include/linux/sched.h 中定义。
2.双向循环链表
哈希表的主要做用是根据进程的pid能够快速地找到对应的进程,但它没有反映进程建立的顺序,也没法反映进程之间的亲属关系,所以引入双向循环链表。每一个进程task_struct结构中的prev_task和next_task域用来实现这种链表。
3.运行队列
当内核要寻找一个新的进程在CPU上运行时,必须只考虑处于可运行状态的进程(即在TASK_RUNNING 状态的进程) ,由于扫描整个进程链表是至关低效的,因此引入了可运行状态进程的双向循环链表,也叫运行队列(runqueue)。
4.进程的运行队列链表
该队列经过task_struct结构中的两个指针run_list链表来维持。队列的标志有两个:一个是“空进程”idle_task,一个是队列的长度。
空进程是个比较特殊的进程,只有系统中没有进程可运行时它才会被执行,Linux将它看做运行队列的头,当调度程序遍历运行队列,是从idle_task开始、至idle_task结束的,在调度程序运行过程当中,容许队列中加入新出现的可运行进程,新出现的可运行进程插入到队尾,这样的好处是不会影响到调度程序所要遍历的队列成员,可见,idle_task是运行队列很重要的标志。另外一个重要标志是队列长度,也就是系统中处于可运行状态(TASK_RUNNING)的进程数目,用全局整型变量nr_running表示,在/kernel/fork.c 中定义。
5.等待队列
顾名思义,就是等待执行的进程所组成的队列。等待队列在内核中有不少用途,尤为对中断处理、进程同步及定时用处更大。
5、内核线程
内核线程或叫守护进程,在操做系统中占据至关大的比例,你能够用“ps”命令查看系统中的进程,这时会发现不少以“d”结尾的进程名,这些进程就是内核线程。内核线程是由kernel_thread ( )函数在内核态下建立。
内核线程也能够叫内核任务,它们周期性地执行,例如,磁盘高速缓存的刷新,网络链接的维护,页面的换入换出等。在Linux中,内核线程与普通进程有一些本质的区别,从如下几个方面能够看出两者之间的差别。
*内核线程执行的是内核中的函数,而普通进程只有经过系统调用才能执行内核中的函数。
*内核线程只运行在内核态,而普通进程既能够运行在用户态,也能够运行在内核态。
*由于内核线程指只运行在内核态,所以,它只能使用大于PAGE_OFFSET(3G)的地址空间。另外一方面,无论在用户态仍是内核态,普通进程可使用4GB的地址空间。
因为kernel_thread包含大部分汇编代码,大体和下面代码等价:
int kernel_thread(int(*fn)(void *),void * arg,unsigned long flags) { pid_t p ; p = clone(0, flags | CLONE_VM); if(p) /* parent */ return p; else{ /* child */ fn(arg) ; exit( ) ; } }
6、进程的权能
Linux 用“权能(capability)”表示一进程所具备的权力。一种权能仅仅是一个标志,它代表是否容许进程执行一个特定的操做或一组特定的操做。这个模型不一样于传统的“超级用户对普通户”模型,在后一种模型中,一个进程要么能作任何事情,要么什么也不能作,这取决于它的有效 UID。
任什么时候候,每一个进程只须要有限种权能,这是其主要优点。所以,即便一位有恶意的用户使用有潜在错误程序,他也只能非法地执行有限个操做类型。
具体权能列表在博客:http://blog.csdn.net/tq08g2z/article/details/77311787?locationNum=3&fps=1