首页 > 代码库 > 进程与进程描述符(task_struct)
进程与进程描述符(task_struct)
一、 进程
进程(Process)
计算机中的程序关于某数据集合上的一次运行活动,是系统进行资源分配和调度的基本单位,是操作系统结构的基础。在早期面向进程设计的计算机结构中,进程是程序的基本执行实体;在当代面向线程设计的计算机结构中,进程是线程的容器。程序是指令、数据及其组织形式的描述,进程是程序的实体。
———————————————————————————————————————————————————————————————
- 释义:一段程序的执行过程
- 特征:动态、独立、异步、并发
- 结构特征:程序、数据和进程控制块
- 相关概念:线程,管程
定义
狭义定义:进程是正在运行的程序的实例(an instance of a computer program that is being executed)。
广义定义:
进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。
它是是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。
进程的概念主要有两点:
第一,进程是一个实体。
‘每一个进程都有它自己的地址空间,一般情况下,包括文本区域(text region)、数据区域(data region)和堆栈(stack region)。文本区域存储处理器执行的代码;数据区域存储变量和进程执行期间使用的动态分配的内存;堆栈区域存储着活动过程调用的指令和本地变量。‘
第二,进程是一个“执行中的程序”。
‘程序是一个没有生命的实体,只有处理器赋予程序生命时(操作系统执行之),它才能成为一个活动的实体,我们称其为进程。‘
特征
动态性:进程的实质是程序在多道程序系统中的一次执行过程,进程是动态产生,动态消亡的。
并发性:任何进程都可以同其他进程一起并发执行
独立性:进程是一个能独立运行的基本单位,同时也是系统分配资源和调度的独立单位;
异步性:由于进程间的相互制约,使进程具有执行的间断性,即进程按各自独立的、不可预知的速度向前推进
结构特征:进程由程序、数据和进程控制块三部分组成。
多个不同的进程可以包含相同的程序:一个程序在不同的数据集里就构成不同的进程,能得到不同的结果;但是执行过程中,程序不能发生改变。
内容
一个计算机系统进程包括(或者说“拥有”)下列数据:
那个程序的可运行机器码的一个在存储器的映像。 分配到的存储器(通常包括虚拟内存的一个区域)。存储器的内容包括可运行代码、特定于进程的数据(输入、输出)、调用堆栈、堆栈(用于保存运行时运数中途产生的数据)。 分配给该进程的资源的操作系统描述符,诸如文件描述符(Unix术语)或文件句柄(Windows)、数据源和数据终端。 安全特性,诸如进程拥有者和进程的权限集(可以容许的操作)。 处理器状态(内文),诸如寄存器内容、物理存储器寻址等。当进程正在运行时,状态通常储存在寄存器,其他情况在存储器。
切换
进行进程切换就是从正在运行的进程中收回处理器,然后再使待运行进程来占用处理器。
这里所说的从某个进程收回处理器,实质上就是把进程存放在处理器的寄存器中的中间数据找个地方存起来,从而把处理器的寄存器腾出来让其他进程使用。那么被中止运行进程的中间数据存在何处好呢?当然这个地方应该是进程的私有堆栈。
让进程来占用处理器,实质上是把某个进程存放在私有堆栈中寄存器的数据(前一次本进程被中止时的中间数据)再恢复到处理器的寄存器中去,并把待运行进程的断点送入处理器的程序指针PC,于是待运行进程就开始被处理器运行了,也就是这个进程已经占有处理器的使用权了。
这就像多个同学要分时使用同一张课桌一样,所谓要收回正在使用课桌同学的课桌使用权,实质上就是让他把属于他的东西拿走;而赋予某个同学课桌使用权,只不过就是让他把他的东西放到课桌上罢了。
在切换时,一个进程存储在处理器各寄存器中的中间数据叫做进程的上下文,所以进程的 切换实质上就是被中止运行进程与待运行进程上下文的切换。在进程未占用处理器时,进程 的上下文是存储在进程的私有堆栈中的。
状态
进程执行时的间断性,决定了进程可能具有多种状态。事实上,运行中的进程可能具有以下三种基本状态。
1)就绪状态(Ready):
进程已获得除处理器外的所需资源,等待分配处理器资源;只要分配了处理器进程就可执行。就绪进程可以按多个优先级来划分队列。例如,当一个进程由于时间片用完而进入就绪状态时,排入低优先级队列;当进程由I/O操作完成而进入就绪状态时,排入高优先级队列。
2)运行状态(Running):
进程占用处理器资源;处于此状态的进程的数目小于等于处理器的数目。在没有其他进程可以执行时(如所有进程都在阻塞状态),通常会自动执行系统的空闲进程。
3)阻塞状态(Blocked):
由于进程等待某种条件(如I/O操作或进程同步),在条件满足之前无法继续执行。该事件发生前即使把处理器资源分配给该进程,也无法运行。
区别
程序
程序是指令和数据的有序集合,其本身没有任何运行的含义,是一个静态的概念。而进程是程序在处理机上的一次执行过程,它是一个动态的概念。
程序可以作为一种软件资料长期存在,而进程是有一定生命期的。程序是永久的,进程是暂时的。
进程更能真实地描述并发,而程序不能;
进程是由进程控制块、程序段、数据段三部分组成;
进程具有创建其他进程的功能,而程序没有。
同一程序同时运行于若干个数据集合上,它将属于若干个不同的进程,也就是说同一程序可以对应多个进程。
在传统的操作系统中,程序并不能独立运行,作为资源分配和独立运行的基本单元都是进程。
线程
进程和线程关系
通常在一个进程中可以包含若干个线程,它们可以利用进程所拥有的资源,在引入线程的操作系统中,通常都是把进程作为分配资源的基本单位,而把线程作为独立运行和独立调度的基本单位,由于线程比进程更小,基本上不拥有系统资源,故对它的调度所付出的开销就会小得多,能更高效的提高系统内多个程序间并发执行的程度。
当下推出的通用操作系统都引入了线程,以便进一步提高系统的并发性,并把它视为现代操作系统的一个重要指标。
控制
进程控制是进程管理中最基本的功能。它用于创建一个新进程,终止一个已完成的进程,或者去终止一个因出现某事件而使其无法运行下去的进程,还可负责进程运行中的状态转换。
创建进程
1.引起创建进程的事件
在多道程序环境中,只有(作为)进程(时)才能在系统中运行。因此,为使程序能运行,就必须为它创建进程。导致一个进程去创建另一个进程的典型事件,可以有以下四类:
1) 用户登录
在分时系统中,用户在终端键入登录命令后,如果是合法用户,系统将为该终端建立一个进程,并把它插入到就绪队列中。
2)作业调度
在批处理系统中,当作业调度程序按照一定的算法调度到某作业时,便将该作业装入到内存,为它分配必要的资源,并立即为它创建进程,再插入到就绪队列中。
3) 提供服务
当运行中的用户程序提出某种请求后,系统将专门创建一个进程来提供用户所需要的服务,例如,用户程序要求进行文件打印,操作系统将为它创建一个打印进程,这样,不仅可以使打印进程与该用户进程并发执行,而且还便于计算出为完成打印任务所花费的时间。
4) 应用请求
在上述三种情况中,都是由系统内核为它创建一个新进程,而这一类事件则是基于应用进程的需求,由它创建一个新的进程,以便使新进程以并发的运行方式完成特定任务。
2.进程的创建过程
一旦操作系统发现了要求创建新进程的事件后,便调用进程创建原语create()按下述步骤创建一个新进程。
1) 申请空白PCB。为新进程申请获得唯一的数字标识符,并从PCB集合中索取一个空白PCB。
2) 为新进程分配资源。为新进程的程序和数据以及用户栈分配必要的内存空间。显然,此时操作系统必须知道新进程所需要的内存大小。
3) 初始化进程控制块。PCB的初始化包括:
①初始化标识信息,将系统分配的标识符和父进程标识符,填入新的PCB中。
②初始化处理机状态信息,使程序计数器指向程序的入口地址,使栈指针指向栈顶。
③初始化处理机控制信息,将进程的状态设置为就绪状态或静止就绪状态,对于优先级,通常是将它设置为最低优先级,除非用户以显式的方式提出高优先级要求。
4) 将新进程插入就绪队列,如果进程就绪队列能够接纳新进程,便将新进程插入到就绪队列中。
进程终止
1.引起进程终止的事件
1)正常结束
在任何计算机系统中,都应该有一个表示进程已经运行完成的指示。例如,在批处理系统中,通常在程序的最后安排一条Hold指令或终止的系统调用。当程序运行到Hold指令时,将产生一个中断,去通知OS本进程已经完成。
2)异常结束
在进程运行期间,由于出现某些错误和故障而迫使进程终止。这类异常事件很多,常见的有:越界错误,保护错,非法指令,特权指令错,运行超时,等待超时,算术运算错,I/O故障。
3)外界干预
外界干预并非指在本进程运行中出现了异常事件,而是指进程应外界的请求而终止运行。这些干预有:操作员或操作系统干预,父进程请求,父进程终止。
- 进程的终止过程
如果系统发生了上述要求终止进程的某事件后,OS便调用进程终止原语,按下述过程去终止指定的进程。
1)根据被终止进程的标识符,从PCB集合中检索出该进程的PCB,从中读出该进程状态。
2)若被终止进程正处于执行状态,应立即终止该进程的执行,并置调度标志为真。用于指示该进程被终止后应重新进行调度。
3)若该进程还有子孙进程,还应将其所有子孙进程予以终止,以防他们成为不可控的进程。
4)将被终止的进程所拥有的全部资源,或者归还给其父进程,或者归还给系统。
5)将被终止进程(它的PCB)从所在队列(或链表)中移出,等待其它程序来搜集信息。
阻塞唤醒
1.引起进程阻塞和唤醒的事件
1)请求系统服务
当正在执行的进程请求操作系统提供服务时,由于某种原因,操作系统并不立即满足该进程的要求时,该进程只能转变为阻塞状态来等待,一旦要求得到满足后,进程被唤醒。
2)启动某种操作
当进程启动某种操作后,如果该进程必须在该操作完成之后才能继续执行,则必须先使该进程阻塞,以等待该操作完成,该操作完成后,将该进程唤醒。
3)新数据尚未到达
对于相互合作的进程,如果其中一个进程需要先获得另一(合作)进程提供的数据才能运行以对数据进行处理,则是要其所需数据尚未到达,该进程只有(等待)阻塞,等到数据到达后,该进程被唤醒。
4)无新工作可做
系统往往设置一些具有某特定功能的系统进程,每当这种进程完成任务后,便把自己阻塞起来以等待新任务到来,新任务到达后,该进程被唤醒。
2.进程阻塞过程
正在执行的进程,当发现上述某事件后,由于无法继续执行,于是进程便通过调用阻塞原语block()把自己阻塞。可见,进程的阻塞是进程自身的一种主动行为。进入block过程后,由于此时该进程还处于执行状态,所以应先立即停止执行,把进程控制块中的现行状态由执行改为阻塞,并将PCB插入阻塞队列。如果系统中设置了因不同事件而阻塞的多个阻塞队列,则应将本进程插入到具有相同事件的阻塞(等待)队列。最后,转调度程序进行重新调度,将处理机分配给另一就绪进程,并进行切换,亦即,保留被阻塞进程的处理机状态(在PCB中),再按新进程的PCB中的处理机状态设置CPU环境。
- 进程唤醒过程
当被阻塞的进程所期待的事件出现时,如I/O完成或者其所期待的数据已经到达,则由有关进程(比如,用完并释放了该I/O设备的进程)调用唤醒原语wakeup(),将等待该事件的进程唤醒。唤醒原语执行的过程是:首先把被阻塞的进程从等待该事件的阻塞队列中移出,将其PCB中的现行状态由阻塞改为就绪,然后再将该PCB插入到就绪队列中。
调度算法
进程的调度算法包括:
实时系统中:FIFO(First Input First Output,先进先出算法),SJF(Shortest Job First,最短作业优先算法),SRTF(Shortest Remaining Time First,最短剩余时间优先算法)。
交互式系统中:RR(Round Robin,时间片轮转算法),HPF(Highest Priority First,最高优先级算法),多级队列,最短进程优先,保证调度,彩票调度,公平分享调度。
阶段
进程是由进程控制块、程序段、数据段三部分组成。一个进程可以包含若干线程(Thread),线程可以帮助应用程序同时做几件事(比如一个线程向磁盘写入文件,另一个则接收用户的按键操作并及时做出反应,互相不干扰),在程序被运行后,系统首先要做的就是为该程序进程建立一个默认线程,然后程序可以根据需要自行添加或删除相关的线程。是可并发执行的程序。在一个数据集合上的运行过程,是系统进行资源分配和调度的一个独立单位,也是称活动、路径或任务,它有两方面性质:活动性、并发性。进程可以划分为运行、阻塞、就绪三种状态,并随一定条件而相互转化:就绪–运行,运行–阻塞,阻塞–就绪。
进程为应用程序的运行实例,是应用程序的一次动态执行。看似高深,我们可以简单地理解为:它是操作系统当前运行的执行程序。在系统当前运行的执行程序里包括:系统管理计算机个体和完成各种操作所必需的程序;用户开启、执行的额外程序,当然也包括用户不知道,而自动运行的非法程序(它们就有可能是病毒程序)。
二、进程描述符
1.概念
在linux中,每一个进程都有一个进程描述符,这个”进程描述符”是一个结构体名字叫做task_struct,在task_struct里面保存了许多关于进程控制的信息。
task_struct是Linux内核的一种数据结构,它会被装载到RAM里并包含进程的信息。每个进程都把它的信息放在task_struct这个数据结构里面,而
2.task_struct内容
标示符:描述本进程的唯一标示符,用来区别其他进程。
状态:任务状态,退出代码,退出信号等。
优先级:相对于其他进程的优先级。
程序计数器:程序中即将被执行的下一条指令的地址。
内存指针:包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
上下文数据:进程执行时处理器的寄存器中的数据。
I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和正在被进程使用的文件列表。
记账信息:可能包括处理器时间总和,使用的时钟总数,时间限制,记账号等。
3.task_struct的分类
调度数据成员
(1) volatile long states; //进程状态
(2) unsigned long flags; //进程标记符
(3) long priority; //用来保存动态优先级
(4) unsigned long rt_priority; //用来保存实时优先级,取值范围为0~99
(5) long counter;
(6) unsigned long policy;
信号处理
(1) unsigned long signal;
(2) unsigned long blocked;
(3) struct signal_struct *sig;
进程队列指针
(1) struct task_struct *next_task,*prev_task;
(2) struct task_struct *next_run,*prev_run;
(3) struct task_struct *p_opptr,*p_pptr;和struct task_struct *p_cptr,*p_ysptr,*p_osptr;
进程标识
(1) unsigned short uid,gid;
(2) int groups[NGROUPS];
(3) unsigned short euid,egid;
(4) unsigned short fsuid,fsgid;
(5) unsigned short suid,sgid;
(6) int pid,pgrp,session;
(7) int leader;
时间数据成员
(1) unsigned long timeout;
(2) unsigned long it_real_value,it_real_iner;
(3) struct timer_list real_timer;
(4) unsigned long it_virt_value,it_virt_incr;
(5) unsigned long it_prof_value,it_prof_incr;
(6) long utime,stime,cutime,cstime,start_time;
信号量数据成员
(1) struct sem_undo *semundo;
(2) struct sem_queue *semsleeping;
进程上下文环境
(1) struct desc_struct *ldt;
(2) struct thread_struct tss;
(3) unsigned long saved_kernel_stack;
(4) unsigned long kernel_stack_page;
文件系统数据成员
(1) struct fs_struct *fs;
(2) struct files_struct *files;
(3) int link_count;
内存数据成员
(1) struct mm_struct *mm;
页面管理
(1) int swappable:1;
(2) unsigned long swap_address;
(3) unsigned long min_flt,maj_flt;
(4) unsigned long nswap;
(5) unsigned long cmin_flt,cmaj_flt,cnswap;
(6) unsigned long old_maj_flt,dec_flt;
(7) unsigned long swap_cnt;
支持对称多处理器方式(SMP)时的数据成员
(1) int processor;
(2) int last_processor;
(3) int lock_depth;
其它数据成员
(1) unsigned short used_math;
(2) char comm[16];
(3) struct rlimit rlim[RLIM_NLIMITS];
(4) int errno;
(5) long debugreg[8];
(6) struct exec_domain *exec_domain;
(7) unsigned long personality;
(8) struct linux_binfmt *binfmt;
(9) int exit_code,exit_signal;
(10) int dumpable:1;
(11) int did_exec:1;
(12) int tty_old_pgrp;
(13) struct tty_struct *tty;
(14) struct wait_queue *wait_chldexit;
进程队列的全局变量
(1) current;
(2) struct task_struct init_task;
(3) struct task_struct *task[NR_TASKS];
(4) unsigned long volatile jiffies;
(5) int need_resched;
(6) unsigned long intr_count;
task_struct的定义
truct task_struct {
volatile long state; //说明了该进程是否可以执行,还是可中断等信息
unsigned long flags; //Flage 是进程号,在调用fork()时给出
int sigpending; //进程上是否有待处理的信号
mm_segment_t addr_limit; //进程地址空间,区分内核进程与普通进程在内存存放的位置不同
//0-0xBFFFFFFF for user-thead
//0-0xFFFFFFFF for kernel-thread
//调度标志,表示该进程是否需要重新调度,若非0,则当从内核态返回到用户态,会发生调度
volatile long need_resched;
int lock_depth; //锁深度
long nice; //进程的基本时间片
//进程的调度策略,有三种,实时进程:SCHED_FIFO,SCHED_RR, 分时进程:SCHED_OTHER
unsigned long policy;
struct mm_struct *mm; //进程内存管理信息
int processor;
//若进程不在任何CPU上运行, cpus_runnable 的值是0,否则是1 这个值在运行队列被锁时更新
unsigned long cpus_runnable, cpus_allowed;
struct list_head run_list; //指向运行队列的指针
unsigned long sleep_time; //进程的睡眠时间
//用于将系统中所有的进程连成一个双向循环链表, 其根是init_task
struct task_struct *next_task, *prev_task;
struct mm_struct *active_mm;
struct list_head local_pages; //指向本地页面
unsigned int allocation_order, nr_local_pages;
struct linux_binfmt *binfmt; //进程所运行的可执行文件的格式
int exit_code, exit_signal;
int pdeath_signal; //父进程终止时向子进程发送的信号
unsigned long personality;
//Linux可以运行由其他UNIX操作系统生成的符合iBCS2标准的程序
int did_exec:1;
pid_t pid; //进程标识符,用来代表一个进程
pid_t pgrp; //进程组标识,表示进程所属的进程组
pid_t tty_old_pgrp; //进程控制终端所在的组标识
pid_t session; //进程的会话标识
pid_t tgid;
int leader; //表示进程是否为会话主管
struct task_struct *p_opptr,*p_pptr,*p_cptr,*p_ysptr,*p_osptr;
struct list_head thread_group; //线程链表
struct task_struct *pidhash_next; //用于将进程链入HASH表
struct task_struct **pidhash_pprev;
wait_queue_head_t wait_chldexit; //供wait4()使用
struct completion *vfork_done; //供vfork() 使用
unsigned long rt_priority; //实时优先级,用它计算实时进程调度时的weight值
//it_real_value,it_real_incr用于REAL定时器,单位为jiffies, 系统根据it_real_value
//设置定时器的第一个终止时间. 在定时器到期时,向进程发送SIGALRM信号,同时根据
//it_real_incr重置终止时间,it_prof_value,it_prof_incr用于Profile定时器,单位为jiffies。
//当进程运行时,不管在何种状态下,每个tick都使it_prof_value值减一,当减到0时,向进程发送
//信号SIGPROF,并根据it_prof_incr重置时间.
//it_virt_value,it_virt_value用于Virtual定时器,单位为jiffies。当进程运行时,不管在何种
//状态下,每个tick都使it_virt_value值减一当减到0时,向进程发送信号SIGVTALRM,根据
//it_virt_incr重置初值。
unsigned long it_real_value, it_prof_value, it_virt_value;
unsigned long it_real_incr, it_prof_incr, it_virt_value;
struct timer_list real_timer; //指向实时定时器的指针
struct tms times; //记录进程消耗的时间
unsigned long start_time; //进程创建的时间
//记录进程在每个CPU上所消耗的用户态时间和核心态时间
long per_cpu_utime[NR_CPUS], per_cpu_stime[NR_CPUS];
//内存缺页和交换信息:
//min_flt, maj_flt累计进程的次缺页数(Copy on Write页和匿名页)和主缺页数(从映射文件或交换
//设备读入的页面数); nswap记录进程累计换出的页面数,即写到交换设备上的页面数。
//cmin_flt, cmaj_flt, cnswap记录本进程为祖先的所有子孙进程的累计次缺页数,主缺页数和换出页面数。
//在父进程回收终止的子进程时,父进程会将子进程的这些信息累计到自己结构的这些域中
unsigned long min_flt, maj_flt, nswap, cmin_flt, cmaj_flt, cnswap;
int swappable:1; //表示进程的虚拟地址空间是否允许换出
//进程认证信息
//uid,gid为运行该进程的用户的用户标识符和组标识符,通常是进程创建者的uid,gid
//euid,egid为有效uid,gid
//fsuid,fsgid为文件系统uid,gid,这两个ID号通常与有效uid,gid相等,在检查对于文件
//系统的访问权限时使用他们。
//suid,sgid为备份uid,gid
uid_t uid,euid,suid,fsuid;
gid_t gid,egid,sgid,fsgid;
int ngroups; //记录进程在多少个用户组中
gid_t groups[NGROUPS]; //记录进程所在的组
//进程的权能,分别是有效位集合,继承位集合,允许位集合
kernel_cap_t cap_effective, cap_inheritable, cap_permitted;
int keep_capabilities:1;
struct user_struct *user;
struct rlimit rlim[RLIM_NLIMITS]; //与进程相关的资源限制信息
unsigned short used_math; //是否使用FPU
char comm[16]; //进程正在运行的可执行文件名
//文件系统信息
int link_count, total_link_count;
//NULL if no tty 进程所在的控制终端,如果不需要控制终端,则该指针为空
struct tty_struct *tty;
unsigned int locks;
//进程间通信信息
struct sem_undo *semundo; //进程在信号灯上的所有undo操作
struct sem_queue *semsleeping; //当进程因为信号灯操作而挂起时,他在该队列中记录等待的操作
//进程的CPU状态,切换时,要保存到停止进程的task_struct中
struct thread_struct thread;
//文件系统信息
struct fs_struct *fs;
//打开文件信息
struct files_struct *files;
//信号处理函数
spinlock_t sigmask_lock;
struct signal_struct *sig; //信号处理函数
sigset_t blocked; //进程当前要阻塞的信号,每个信号对应一位
struct sigpending pending; //进程上是否有待处理的信号
unsigned long sas_ss_sp;
size_t sas_ss_size;
int (*notifier)(void *priv);
void *notifier_data;
sigset_t *notifier_mask;
u32 parent_exec_id;
u32 self_exec_id;
spinlock_t alloc_lock;
void *journal_info;
};
博客参照于:http://blog.csdn.net/lf_2016/article/details/54347820
进程百度百科:http://baike.baidu.com/item/%E8%BF%9B%E7%A8%8B#2_1
进程与进程描述符(task_struct)