一.进程(或者称为“任务”)简介
进程是OS最基本的抽象之一,通常进程包括“可执行程序代码”,“其他资源”(如:打开的文件,挂起的信号,内核内部数据,处理器状态,地址空间,一个或多个执行线程等)
二.执行线程简介
执行线程(或称线程)是进程中活动的对象,内核调度的对象是线程,而不是进程,每个线程中都有一个独立的程序计数器,进程栈,进程寄存器
三.进程虚拟机制简介
进程提供了两种虚拟机制(后面的章节,我们还会学习哈~):1.虚拟处理器:给进程一种假象,让这些进程觉得自己独享处理器(这个需要控制好时间片哈~不能太长也不能太短)
2.虚拟内存:让进程再获取和使用内存时觉得自己拥有整个系统的所有内存资源
(注:线程之间可以共享虚拟内存,但拥有各自的虚拟处理器)
四.进程在Linux内核中表示的数据结构task_struct
1.内核把进程存放在“任务队列”(一个双向循环链表的结构)中,链表中每一项都是类型为“task_struct(进程描述符)”的结构(<linux/sched.h>中)
2.进程的task_struct是通过slab分配器分配生成的
3.内核通过一个唯一的进程标识值或者PID来标识每个进程。PID是一个数,int类型(最大默认为32768 [short int最大值])
structtask_struct {
unsigned longstate;(判断进程状态的参数)
....
structtask_struct * parent; (指向父进程,涉及资源共享等问题)
struct list_head tasks; (任务链表)
pid_t pid; (进程标识值)
....
....
}
五.进程七大状态
Linux中的进程有7种状态,进程的task_struct结构的state字段指明了该进程的状态。
可运行状态(TASK_RUNNING): 1.正在执行 2.在运行队列中等待执行
可中断的等待(TASK_INTERRUPTIBLE)[进程睡眠中]: 1.等待某些条件的达成,条件一达成,内核会把进程状态设置为运行状态(Running),处于此状态的进程也会因为接收到信号而提前被唤醒并投入运行
不可中断的等待(TASK_UNINTERRUPTIBLE):除了不会因为接到信号而被唤醒从而投入运行外,其他的和(可中断的等待状态一样)
暂停状态(TASK_STOPPED)[停止]: 1.进程没有投入运行也不能投入运行
跟踪状态(TASK_TRACED):进程被调试器暂停或监视。
僵死状态(EXIT_ZOMBIE):进程被终止,但父进程未调用wait类系统调用。
僵死撤销状态(TASK_DEAD):父进程发起wait类系统调用,进程由系统删除。
六.进程上下文和进程家族树
进程上下文:
当一个程序执行了系统调用或者触发了某个异常,它就陷入了内核空间(内核态),称内核“代表进程执行”并处于进程上下文中
系统调用和异常处理程序是对内核明确定义的接口,进程只有通过这些接口才能进入内核执行,对内核的所有访问都必须调用这些接口
进程家族树:
所有的进程都是PID为1的Init进程的后代,内核在系统启动的最后阶段启动init进程,该进程读取“初始化脚本”并执行其他相关程序,最终完成系统启动的整个过程
每个进程描述符(task_struct)中都包含一个指向其父进程的指针(parent),和一个包含所有子进程的链表(children)
关于init进程:
七.进程状态转换图(引用网上图片)
八.进程的创建
创建进程的方法:
1.其他操作系统:首先在新的地址空间里创建进程,读入可执行文件,最后开始执行
2.Unix/Linux:用两个函数 fork() 和 exec() 来执行,完成进程创建工作
fork():该调用通过复制一个现有进程来创建一个全新的进程(父进程和子进程的区别仅仅在于PID不同,其他资源的话,父进程和子进程一样)
调用fork()进程的成为父进程,新产生的进程成为子进程,在调用结束后,在返回调用位置,父进程恢复执行,子进程开始执行,fork()系统调用从内核返回两次(一次返回父进程,一次返回子进程)
exec(): 负责读取可执行文件并将其载入地址空间开始运行
(exec()这个家族包括: execve(),execlp(),execle(), execv(), execvp() 等系统调用)
fork()详解:http://www.cnblogs.com/bastard/archive/2012/08/31/2664896.html
九.进程的终结
当一个进程终结时,内核必须释放它所有的资源并告知其父进程进程的析构发生在它调用exit()后(既可以显式调用,也可以隐式调用[主函数返回时调用])或者遇到异常,也会被动终结
do_exit()(定义于kernel/exit.c中):http://hi.baidu.com/zengzhaonong/item/24cc74c0e74a8b2d46d5c023
十.进程描述符的删除
当调用do_exit()之后,进程已经处于僵死状态,但仍保留了它的进程描述符(能让父进程得到它的状态信息)
但仍保留它的进程描述符(让父进程能得到它的信息)在父进程获取已终结的子进程信息后,或者通知内核它并不关注
那些信息后,子进程的task_struct结构才被释放。
wait()这一族函数都是通过唯一的一个系统调用wait4()实现的,调用时会挂起调用它的进程,直到有一个子进程退出,此时函数
会返回该子进程的PID,当最终要释放进程的描述符时,会调用release_task()