《Linux内核设计与实现》第3章读书整理

                               第三章、进程管理

 

3.1进程

1.进程就是处于执行期的程序,但进程并不仅仅局限于一段可执行程序代码

2.执行线程:

  简称线程,是在进程中活动的对象。每个线程都拥有一个独立的程序计数器、进程栈和一组进程计数器。

3.在现代操作系统中,进程提供两种虚拟机制:虚拟处理器和虚拟内存。

4.程序本身并不是进程,进程是处于执行期的程序以及相关的资源的总称。

5.fork():使进程在创建它的时候开始存活;

 Exec():创建新的地址空间,并把新的程序载入其中;

 Exit():退出执行。

 

3.2进程描述符及任务结构

1.进程描述符:

内核把进程的列表存放在叫做任务队列的双向循环链表中。链表中的每一项都是类型为task_struct,称为进程描述符的结构。

2.进程描述符中包含的数据能完整地描述一个正在执行的程序:它打开的文件,进程的地址空间,挂起的信号,进程的状态,还有其他更多信息。

3.2.1分配进程描述符

   Linux通过slab分配器分配task_struct结构。

   由于现在用slab分配器动态生成task_struct,所以只需在栈底或栈顶创建一个新的结构struct thread_info。

   每个任务的thread_info结构在它的内核栈的尾端分配。结构中task域中存放的是指向该任务实际task_struct的指针。

3.2.2进程描述符的存放

内核通过一个唯一的进程标识值或PID来标识每个进程。

在内核中,访问任务通常需要获得指向其task_struct的指针。

3.2.3进程状态

(五种进程状态)

TASK_RUNNING(运行)

TASK_INTERRUPTIBLE(可中断)

TASK_UNINTERRUPTIBLE(不可中断)

_TASK_TRACED

_TASK_STOPPED(停止)

3.2.4设置当前进程状态

使用set_task_state(task,state)函数

3.2.5进程上下文

    可执行程序代码是进程的重要组成部分。这些代码从一个可执行文件载入到进程的地址空间执行。一般程序在用户空间执行。当一个

程序执行了系统调用或者触发了某个异常,它就陷入了内核空间,此时,我们称内核“代表进程执行”并处于进程上下文中。

3.2.6进程家族树

继承关系

 

3.3进程创建

Unix采用了与众不同的实现方式,它把其他操作系统的步骤分解到两个单独的函数中去执行:fork()和exec();

Fork()通过拷贝当前进程创建一个子进程。

Exec()函数负责读取可执行文件并将其载入地址空间开始运行。

3.3.1写时拷贝

只在有需要写入的时候,数据才会被复制,从而使各个进程拥有各自的拷贝。

3.3.2 fork()

Linux通过clone()系统调用实现fork()

do_fork完成了创建中的大部分工作,该函数调用copy_process()函数,然后让进程开始运行。

3.3.3 vfork()

除了不拷贝父进程的页表项外,vfork()系统调用和fork()的功能相同。

vfork()系统调用的实现是通过向clone()系统调用传递一个特殊标志来进行的。

 

3.4线程在Linux中的实现

3.4.1创建线程

线程的创建和普通进程的创建类似,只不过在调用clone()的时候需要传递一些参数标志来指明需要共享的资源:

Clone(CLONE_VM | CLONE_FS | CLONE_FILES | CLONE_SIGHAND,0);

传递给clone()的参数标志决定了新创建进程的行为方式和父子进程之间共享的资源种类。

3.4.2内核线程

在后台执行一些操作

 

3.5进程终结

3.5.1删除进程描述符

    进程终结时所需的清理工作和进程描述符的删除被分开执行。在父进程获得已经终结的子进程的信息后,或者通知内核它并不关注

那些信息后,子进程的task_struct结构才能被释放。

3.5.2孤儿进程造成的进退维谷

    如果父进程在子进程之前退出,必须有机制来保证子进程能找到一个新的父进程,否则这些成为孤儿的进程就会在退出时永远处于

僵死状态,白白的耗费内存。

posted on 2016-03-31 13:05  hzy_dky  阅读(173)  评论(0编辑  收藏  举报