进程管理
定义
- 进程就是处于执行期间的程序(还包括打开的文件,挂起的信号,内核内部数据,处理器状态,一个或多个具有内存映射的内存地址空间,及一个或多个执行的线程,存放全局变量的数据段等)。进程是处于执行期的程序以及相关资源的总称。
特性
- 线程是进程中活动的对象。每个线程都拥有独立的程序计数器、进程栈、进程寄存器。
- 内核的调度对象是线程
- 进程提供两种虚拟机之:虚拟处理器,虚拟内存。
- 同一个进程里的线程共享虚拟内存,但各自拥有独立的虚拟处理器
进程描述符及任务结构
内核把进程的列表存放在任务队列(双向循环列表)中。
链表中的每一项都是类型为 task_struct (进程描述符)。
进程描述符包含一个具体进程的所有信息。
- 分配进程描述符
linux通过slab分配器分配task_struct机构。这样可以达到对象复用和缓存着色的目的
进程状态
系统中的每个进程必然处于五种进程状态中的一种:
- TASK_RUNNING —— 进程是可执行的:正在执行或者在运行队列中等待执行。
- TASK_INTERRUPTIBLE —— 进程正在睡眠,等待某些条件的达成。
- TASK_UNINTERRUPTIBLE —— 等待时进程不可中断,对信号不作响应。
- _TASK_TRACKED —— 被其他进程跟踪的进程。
- _TASK_STOPED —— 进程停止执行,进程没有投入运行,也不能运行。
设置当前进程状态
set_task_state(task,state); /*将任务task的状态 设置为 state*/
set_current_state(state); /* 与上面函数等价 */
在SMP系统中使用这个函数;
否则等价于
task->state = state;
进程上下文
当一个程序调执行了系统调用或者触发了某个异常,它就陷入了内核空间。此时,我们称内核“代表进程执行”并处于进程上下文中。
进程家族树
每个进程必有一个父进程,每个进程可以有0个或者多个子进程。进程间的关系存在进程描述符中。每个task_struct 都包含有一个指向其父进程task_struct的指针parent。还有一个称为chaildren的子进程链表。
对于当前进程,可以通过如下代码获取其父进程的进程描述符:
struct task_struct *my_parent = current->parent;
访问子进程:
struct task_struct *task;
struct list_head *list;
list_for_each(list, ¤t->children)
{
task = list_entry(list,struct task_struct,sibling);//task指向当前的某一个进程
}
init进程的进程符是init_task(静态分配)。获取所有进程之间的关系可用如下代码:
struct task_struct *task;
for(task = current;task != init_task;task = task->parent)
;
/*task最终指向init进程*/
通过进程链表获指定进程,如下:
list_entry(task->tasks.next,struct task_struct,tasks) //获取下一个进程
list_entry(task->tasks.prev,struct task_struct,task)//获取上一个进程
其中:task.next task.prev 都是宏定义。
而for_each_process(task)宏可以访问整个队列。每次访问任务指针都会指向链表中的下一个元素。
struct task_struct *task;
for_each_process(task)
{
/*打印出每一个任务的名字和PID*/
printk("%s [%d ]\n",task->com,task->pid);
}
进程创建
调用了两个函数:fork(),exec();
- 过程:fork()通过拷贝当前进程创建一个子进程。exec()函数负责读取可执行文件并将其在如地址空间运行。
- 特点:fork()之后的子进程与父进程的PID(每个进程都是唯一的)、PPID(父进程的进程号)和某些资源和统计量(例如:挂起的信号)。
写时拷贝
- 定义:写时拷贝是一种可以推迟甚至免除拷贝数据的技术。内核此时并不复制整个进程地址进程空间,而是让父进程,子进程烘箱一个拷贝。只有在写入的时候,数据才会被复制。
fork()
P27
vfork()
p28
线程
在linux内核中线程都被当做进程实现。线程仅仅是与其他进程共享某些资源的进程。每个线程都拥有唯一隶属于自己的task_struct.
创建线程
与进程的区别在于clone()的参数不一样。指定了需要共享的资源。
进程终结
当一个进程终结时,内核释放它所占有的资源,并告知其父进程。
当父进程死于子进程之前,会自动找父进程。如果找不到就会让init进程做父进程。