《linux内核设计与实现》读书笔记第三章
第3章 进程管理
3.1 进程
1、进程
进程就是处于执行期的程序。
进程包括:
- 可执行程序代码
- 打开的文件
- 挂起的信号
- 内核内部数据
- 处理器状态
- 一个或多个具有内存映射的内存地址空间
- 一个或多个执行线程
- 用来存放全局变量的数据段
- ……
实际上,进程就是正在执行的程序代码的实时结果
2、执行线程
- 简称线程,是在进程中活动的对象。
- 每个线程都拥有一个独立的程序计数器、进程栈和一组进程寄存器。
- 内核调度的对象是线程,而不是进程。
进程提供两种虚拟机制:
虚拟处理器和虚拟内存。
在线程之间可以共享虚拟内存,但每个都拥有各自的虚拟处理器。
3、fork系统调用 该系统调用通过复制一个现有进程来创建一个全新的进程。 在返回点的相同位置上 fork()实际上是由clone()系统调用实现的。
3.2 进程描述符及任务结构
1、内核把进程的列表存放在叫做任务队列的双向循环链表中。
链表中的每项都是类型为task_ struct称为进程描述符的结构,该结构定义在<linux/sched.h>文件中。
2、进程描述符中包含一个具体进程的所有信息。
3、进程描述符中包含:
- 它打开的文件
- 进程的地址空间
- 挂起的信号
- 进程的状态
- 其他更多信息
3.2.1 分配进程描述符
1、Linux以通过slab分配器分配task_ struct结构,这样能达到对到对象复用和缓存着色的目的。
2、struct_ thread_ info在文件<asm/thread_ info.h>中定义。
3、每个任务的thread_info结构在他的内核栈的尾端分配。
3.2.2 进程描述符的存放
1、内核通过一个唯一的进程标识值或PID来标识每个进程。
- PID最大值的限制在<linux/threads.h>中定义
- 系统管理员可以通过修改/proc/sys/kernel/pid_max来提高上限。
2、硬件体系结构不同,该宏的实现也不同。
- 可以拿出―个专门寄存器来存放指向当前进程task_ struct的指针,用于加快访问速度。
- 在内核的尾端创建thread_ info结构,通过计算偏移间接地查找task_ struct结构。
3.2.3 进程状态
进程描述符中state域描述了进程的当前状态。
五种进程状态:
- TASK_ RUNNING (运行):
进程是可执行;它或者正在执行,或者在运行队列中等待执行——进程在用户空间中执行的唯一可能的状态。- TASK_ INTERRUPTIBLE (可中断):
进程正在睡眠,等待某些条件达、- TASK_ UNINTERRUPTIBLE (不可中断):
另一种阻塞状态,处于该状态的进程只有当资源有效时被唤醒,不能通过信号或定时中断唤醒。- TASK_ STOPPED (停止):
进程停止执行;进程没有投入运行也不能投入运行,常见信号:SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU。- TASK_ TRACED:
被其他进程跟踪的进程。
3.2.4 设置当前进程状态
set_ task_ state(task,state)函数:
- 该函数将指定的进程设置为指定的状态,会设置内存屏障来强制其他处理器作重新排序。
- set_ current_ state(task,state)和set_ task_ state(task,state)含义是等同的。
3.2.5 进程上下文
- 内核“代表进程执行”并处于进程上下文中——当一个程序调执行了系统调用或者触发了某个异常,它就陷入了内核空间。
- 在此上下文中current宏是有效的。
- 系统调用和异常处理程序是对内核明确定义的接口。进程只有通过这些接口才能陷入内核执行——对内核的所有访问都必须通过这些接口。
3.2.6 进程家族树
1、Unⅸ系统的进程之间存在—个明显的继承关系。
- 所有的进程都是PID为1的init进程的后代。
- 内核在系统启动的最后阶段启动init进程。
- 该进程读取系统的初始化脚本并执行其他的相关程序,最终完成系统启动的整个过程。
2、init进程的进程描述符是作为init_task静态分配的。
3、for_ each_ process(task)宏提供了依次访问整个任务队列的能力。
3.3 进程创建
产生进程的机制:
其他操作系统中:
- 首先在新的地址空间里创建进程,
- 读入可执行文件
- 最后开始执行。
在linux系统中——使用fork()和exec()函数
- fork()函数:通过拷贝当前进程创建一个子进程。
- exec()函数:负责读取可执行文件并将其载入地址空间开始运行。
3.3.1 写时拷贝
1、Linux的fork()使用写时拷贝页实现——让父进程和子进程共享同一个拷贝。
- 写时拷贝是一种可以推迟甚至免除拷贝数据的技术。
- 资源的复制只有在需要写入的时候才进行,在此之前,只是以只读方式共享。
fork()的实际开销就是复制父进程的页表以及给子进程创建唯一的进程描述符。
3.3.2 fork()
1、通过clone()系统调用实现fork(),clone()去调用do_ fork()。
do_ fork完成创建中大量工作,定义在kernel/fork.c文件中。
2、copy_ process()完成的工作:
- 调用duptaskstruct()为新进程创建一个内核栈、threadinfo结构和taskstruct,这些值与当前进程的值相同,此时,子进程和父进程的描述符是完全相同的。
- 检查并确保新创建这个子进程后,当前用户所拥有的进程数目没有超出给它分配的资源的限制。
- 子进程着手使自己与父进程区别开来,进程描述符内的许多成员都要被清0或设为初始值,那些不是继承而来的进程描述符成员,主要是统计信息,task_struct中的大多数数据都依然未被修改。
- 子进程的状态被设置为TASK_UNINTERRUPTIBLE,以保证它不会投入运行。
- copyprocess()调用copyflags以更新task_struct的flags成员。
- 调用alloc_pid()为新进程分配一个有效的PID。
- 根据传递给clone()的参数标志,copy_process()拷贝或共享打开的文件、文件系统信息、信号处理函数、进程地址空间和命名空间等。
- 最后,copy_ process()做扫尾工作并返回一个指向子进程的指针。
3.3.3 vfork()
1、vfork()与fork()很类似,实现是通过向clone()系统调用传递一个特殊标志来进行。
2、好处是不用拷贝父进程的页表项,不过理想情况下,系统最好不要调用vfork()。
3.4 线程在Linux中的实现
1、线程机制提供了在同―程序内共享内存地址空间运行的―组线程,线程机制支持并发程序设计技术。
2、不同系统中线程机制的比较:
在其他系统中: - 线程被抽象成一种消耗较少的资源,运行迅速的执行单元。 在linux系统中: - 线程只是一种进程间共享资源的手段。
3.4.1 创建线程
1、线程的创建在调用clone()时需要传递一些参数标志来指明所需要共享的资源。
2、clone()参数标志决定新创建进程的行为方式和父子进程之间共享的资源种类。
3.4.2 内核线程
1、内核线程——独立运行在内核空间的标准进程。
2、内核线程和普通的进程间的区别在于内核线程没有独立的地址空间。
3、在Linux系统上运行ps -ef命令,你可以看到内核线程。
4、内核是通过从kthreadd内核进程中衍生出所有新的内核线程来自动处理这一点的,在<linux/kthreadd>中申明有接口。
新的任务是由kthread内核进系统调用程通过clone()而创建的。
5、内核退出机制:
- 内核线程启动后一直运行知道调用do_exit()退出.
- 内核其它部分调用kthread_stop()退出。
3.5 进程终结
1、进程的析构是自身引起的。
2、进程终结会调用do_ exit函数,该函数永不返回。
3、僵死进程存在的唯一目的就是向它的父进程提供信息。
3.5.1 删除进程描述符
1、在linux系统中,进程终结时所需要的清理工作和进程描述符的删除被分开执行。
2、调用release_task函数——最终释放进程描述符。
3.5.2 孤儿进程造成的进退维谷
1、如果父进程在子进程之前退出,必须有机制来保证子进程能找到一个新的父亲,否则这些成为孤儿的进程就会在退出时永远处于僵死状态。
2、解决方法是给子进程在当前线程组内找一个线程作为父亲,如果不行,就让init做它们的父进程。在doexit()中会调用exitnotify(),该函数会调用forgetoriginalparent(),而后者会调用findnewreaper()来执行寻父。
小结
本章的主要内容——进程
- 进程为何如此重要
- 进程与线程之间的关系
- 进程的一般特性
- Linux如何存放和表示进程
- 如何创建进程
- 如何把新的执行映像装入到地址空间
- 如何表示进程的层次关系
- 父进程又是如何收集其后代的信息
- 进程最终如何消亡。
问题
1、什么是slab分配器?
- slab是Linux操作系统的一种内存分配机制。
- slab分配器是基于对象进行管理的,相同类型的对象归为一类,每当要申请这样一个对象,slab分配器就从一个slab列表中分配一个这样大小的单元出去,而当要释放时,将其重新保存在该列表中。
- slab分配器并不丢弃已分配的对象,而是释放并把它们保存在内存中。当以后又要请求新的对象时,就可以从内存直接获取而不用重复初始化。
- 对象高速缓存的内存区被划分为多个slab,每个slab由一个或多个连续的页框组成,这些页框中既包含已分配的对象,也包含空闲的对象。
- 在cache和object中加入slab分配器,是在时间和空间上的折中方案。
2、什么是析构?
- 析构函数名也应与类名相同,只是在函数名前面加一个位取反符~,以区别于构造函数。
- 它不能带任何参数,也没有返回值(包括void类型)。
- 只能有一个析构函数,不能重载。
- 如果用户没有编写析构函数,编译系统会自动生成一个缺省的析构函数,它也不进行任何操作。所以许多简单的类中没有用显式的析构函数
参考资料
1、slab百度百科
2、析构函数百度百科
3、《Linux内核设计与实现》第三章
《linux内核设计与实现》读书笔记第三章的更多相关文章
- Linux内核设计与实现 读书笔记 转
Linux内核设计与实现 读书笔记: http://www.cnblogs.com/wang_yb/tag/linux-kernel/ <深入理解LINUX内存管理> http://bl ...
- 《Linux内核设计与实现》课本第三章自学笔记——20135203齐岳
<Linux内核设计与实现>课本第三章自学笔记 进程管理 By20135203齐岳 进程 进程:处于执行期的程序.包括代码段和打开的文件.挂起的信号.内核内部数据.处理器状态一个或多个具有 ...
- Linux内核设计与实现 读书笔记
第三章 进程管理 1. fork系统调用从内核返回两次: 一次返回到子进程,一次返回到父进程 2. task_struct结构是用slab分配器分配的,2.6以前的是放在内核栈的栈底的:所有进程的ta ...
- Linux内核设计与实现 总结笔记(第二章)
一.Linux内核中的一些基本概念 内核空间:内核可独立于普通应用程序,它一般处于系统态,拥有受保护的内存空间和访问硬件设备的所有权限.这种系统态和被保护起来的内存空间,称为内核空间. 进程上下文:当 ...
- Linux内核设计与实现读书笔记(8)-内核同步方法【转】
转自:http://blog.chinaunix.net/uid-10469829-id-2953001.html 1.原子操作可以保证指令以原子的方式执行——执行过程不被打断.内核提供了两组原子操作 ...
- Linux内核设计与实现——读书笔记2:进程管理
1.进程: (1)处于执行期的程序,但不止是代码,还包括各种程序运行时所需的资源,实际上进程是正在执行的 程序的实时结果. (2)程序的本身并不是进程,进程是处于执行期的程序及其相关资源的总称. (3 ...
- Linux内核设计与实现——读书笔记1:内核简介
内核:有的时候被称管理者或者操作系统核心,通常内核负责响应中断的中断服务程序, 负责管理多个进程从而分享处理器时间的调度程序,负责管理进程地址空间德内存管理程序 和网络,进程间通信等系统服务程序共同组 ...
- Linux内核设计与实现 总结笔记(第九章)内核同步介绍
在使用共享内存的应用程序中,程序员必须特别留意保护共享资源,防止共享资源并发访问. 一.临界区和竞争条件 1.1 临界区和竞争条件 所谓临界区就是访问和操作共享数据代码段.多个执行线程并发访问同一个资 ...
- 《Linux内核设计与分析》第六周读书笔记——第三章
<Linux内核设计与实现>第六周读书笔记——第三章 20135301张忻估算学习时间:共2.5小时读书:2.0代码:0作业:0博客:0.5实际学习时间:共3.0小时读书:2.0代码:0作 ...
- 《Linux内核设计与实现》课本第四章自学笔记——20135203齐岳
<Linux内核设计与实现>课本第四章自学笔记 进程调度 By20135203齐岳 4.1 多任务 多任务操作系统就是能同时并发的交互执行多个进程的操作系统.多任务操作系统使多个进程处于堵 ...
随机推荐
- OA
OA(政府) http://zw.wuzhitong.com/oa_wuzhitong/index.asp http://www.wuzhitong.com/Information_ZW.html O ...
- [Sdoi2014]旅行 题解
题目大意: 给出一个n个点的数,和m次操作.每个点有颜色和权值. 每次操作分4种 1:修改一个点的颜色 2:修改一个点的权值 3:询问从x到y的路径上,和x相同颜色的点的权值和(保证x,y同颜色) 4 ...
- NOIp 2013 #1 积木大赛 Label:有趣的模拟
题目描述 春春幼儿园举办了一年一度的“积木大赛”.今年比赛的内容是搭建一座宽度为n的大厦,大厦可以看成由n块宽度为1的积木组成,第i块积木的最终高度需要是hi. 在搭建开始之前,没有任何积木(可以看成 ...
- 《深入浅出Windows Phone 8.1 应用开发》基于Runtime框架全新升级版
<深入浅出Windows Phone 8.1 应用开发>使用WP8.1 Runtime框架最新的API重写了上一本<深入浅出Windows Phone 8应用开发>大部分的的内 ...
- 【HDU】3516 Tree Construction
http://acm.hdu.edu.cn/showproblem.php?pid=3516 题意:平面n个点且满足xi<xj, yi>yj, i<j.xi,yi均为整数.求一棵树边 ...
- Kafka剖析(一):Kafka背景及架构介绍
http://www.infoq.com/cn/articles/kafka-analysis-part-1/ Kafka是由LinkedIn开发的一个分布式的消息系统,使用Scala编写,它以可水平 ...
- asp.net mvc本地程序集和GAC的程序集冲突解决方法
一个从asp.net mvc 3升级到asp.net mvc 4的项目发生了如下错误: [A]System.Web.WebPages.Razor.Configuration.HostSection c ...
- 项目管理gitflow的用法(转)
在这里主要讲一下我在项目中用到的关于gitflow的用法. 公司的项目中,专门有一台用来存放版本库的服务器,路径是在默认的安装目录/opt/git/,那么在使用的时候,如果你是一个功能模块或者是一 ...
- lua语法备忘录
1.三元表达式 a?b:c => a and b or c 2.循环数组 local keys = args.kvs:get_keys() local arr = xstring.split(k ...
- Oracle 字符串函数
平常我们用Oracle主要有两种字符串类型1.char始终为固定的长度,如果设置了长度小于char列的值,则Oracle会自动用空格填充的.当比较char时,Oracle用空格将其填充为等长,再进行比 ...