第三章 进程管理

总结

  1. fork创造的子进程复制了父进程资源,包括内存及进程描述符的内容,资源的复制而不是指针的复制。

  2. vfork的行为更像一个线程(指没有自已独立的内存空间),更明显的是vfork的调用将挂起当前进程(即父进程)。

  3. clone根据flag的不同可以实现不同的功能。

  4. 只要退出,最终都调用了do_exit。

3.1 进程

  1. 进程:是处于执行期的程序以及它所包含的资源的总称。

  2. 线程:是在进程中活动的对象。

  3. 每个线程都拥有一个独立的程序计数器、进程栈和一组进程寄存器。

  4. 内核调度的对象是线程,而不是进程。

3.2 进程描述符及任务结构

  1. 进程描述符的结构:task_struct,定义在<linux/sched.h>中,包含一个具体进程的所有信息。

  2. task_struct 就是指 PCB (进程控制块)。

3.2.1 分配进程描述符

  1. thread_info结构在文件<asm/thread_info.h>中。

3.2.2 进程描述符的存放

3.2.3 进程状态

 1.TASK_RUNNING (运行):无论进程是否正在占用 CPU ,只要具备运行条件,都处于该状态。 事实上, Linux 是将就绪态和运行态合并为了一种状态。
2.TASK_INTERRUPTIBLE (可中断阻塞):在资源有效时被唤醒,也可以通过信号或定时中断唤醒。
3.TASK_UNINTERRUPTIBLE (不可中断阻塞):另一种阻塞状态,处于该状态的进程只有当资源有效时被唤醒,不能通过信号或定时中断唤醒。
4.TASK_STOPPED (暂停):第三种阻塞状态,进程被停止,通常是通过接收一个信号SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU。
5.TASK_ZOMBILE (僵死):进程已结束但尚未消亡,已经释放了大部分资源, PCB 仍未被释放,在task数据中仍然保留task_struct结构。一旦父进程调用了wait4(),进程描述符就会被释放。

3.2.4 设置当前进程状态

 set_task_state(task, state);        /* 设置任务 'task' 的状态变成 'state' */

3.2.5 进程上下文

  1. 内核“代表进程执行”并处于进程上下文中。

  2. 此上下文中current宏有效。

3.2.6 进程家族树

 1.获得父进程的进程描述符:
struct task_struct *my_parent = current->parent; 2.依次访问子进程:
struct task_struct *task;
struct list_head *list; list_for_each(list, &current->children) {
task = list_entry(list, struct task_struct, sibling);
/* task指向当前某个子进程*/
} 3.获取链表中的下一个进程:
list_entry(task->tasks.next, struct task_struct, tasks) 4.获取链表中的前一个进程:
list_entry(task->tasks.prev, struct task_struct, tasks) 5.宏for_each_process(task),提供了依次访问整个任务队列的能力, struct task_struct *task; for_each_process(task) {
/* 打印出每个任务名称和pid*/
printk("%s[%d]\n", task->comm, task->pid);
}

3.3 进程创建

3.3.1 写时拷贝

  1. fork() 和 exec()

  2. fork():通过拷贝当前进程创建一个子进程。

  3. exec():负责读取可执行文件并将其载入地址空间开始运行。

3.3.2 fork()

  1. 通过clone()系统调用实现fork()。

  2. do_fork完成创建中大量工作,定义在kernel/fork.c文件中。

  3. 调用copy_process()函数让进程开始运行。(具体工作很有意思详见《Linux内核设计与实现》第27页)

3.3.3 vfork()

  1. 与fork()很类似。

  2. 实现是通过向clone()系统调用传递一个特殊标志来进行。(具体工作很有意思详见《Linux内核设计与实现》第28页)

3.4 线程在Linux中的实现

3.4.1 创建线程

  1. 在调用clone()需传递一些参数标志指明共享资源。
clone(CLONE_VM | CLONE_FS | CLONE_SIGHAND, 0);
新建的进程和他的父进程就是线程。
  1. 一个普通的fork()。
clone(SIGHAND, 0);
  1. vfork()的实现。
clone(CLONE_VFORK | CLONE_VM | SIGHAND, 0);
  1. clone()参数标志决定新创建进程的行为方式和父子进程之间共享的资源种类。(具体参数标识详见《Linux内核设计与实现》第29-30页)

3.4.2 内核线程

  1. 内核线程只能由其他内核线程创建。

  2. 内核通过从kthreadd内核进程中衍生出所有新内核线程来自动处理。

  3. 在<linux/kthread.h>中声明接口。

  4. 新的任务是由kthread内核进系统调用程通过clone()而创建的。

  5. 内核线程启动后一直运行知道调用do_exit()退出,或者内核其它部分调用kthread_stop()退出。

3.5 进程终结

  1. 进程的退出一般是显示或隐式地调用了exit(),或者接受了某种信号。

  2. 只要退出,最终都调用了do_exit()(具体完成的繁琐工作详见《Linux内核设计与实现》第31页)。

3.5.1 删除进程描述符

  1. wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。

  2. 最终需要释放进程描述符时,release_task()会被调用(具体需要完成的工作详见《Linux内核设计与实现》第32页)

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

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

  2. 解决方法是给子进程在当前线程组内找一个线程作为父亲,如果不行,就让init做它们的父进程。在do_exit()中会调用exit_notify(),该函数会调用forget_original_parent(),而后者会调用find_new_reaper()来执行寻父。

  3. 遍历了两个链表:子进程链表和ptrace子进程链表,给每个子进程设置新的父进程。

参考资料

  1. 《Linux内核设计与实现》第3版

  2. http://blog.csdn.net/tobyaries/article/details/8239580

2013337朱荟潼 Linux第三章读书笔记——进程管理的更多相关文章

  1. 2013337朱荟潼 Linux第五章读书笔记——系统调用

    摘要: [20135337朱荟潼]原创作品转载请注明出处 第五章 系统调用 5.1 与内核通信 中间层 作用三个:1.为用户空间提供一种硬件的抽象接口:2.保证系统稳定和安全:3.除异常和陷入,是内核 ...

  2. 2013337朱荟潼 Linux第四章读书笔记——进程调度

    第4章 进程调度 0. 总结 调度:调度是一个平衡的过程.一方面,它要保证各个运行的进程能够最大限度的使用CP:另一方面,保证各个进程能公平的使用CPU. 调度功能:决定哪个进程运行以及进程运行多长时 ...

  3. 2013337朱荟潼 Linux第十八章读书笔记——调试

    第十八章 调试 0.总结 oops 内核的调试配置 用Git进行二分搜索 bug总会有,简洁描述发给LKML 1. 准备开始 在用户级的程序里,bug表现比较直接:在内核中却不清晰. 2. 内核中的b ...

  4. 20135337朱荟潼 Linux第三周学习总结 ——Linux内核源代码简介

    朱荟潼 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课http://mooc.study.163.com/course/USTC 1000029000 知识笔记 1.ar ...

  5. 20135337朱荟潼 Linux第六周学习总结——进程的描述和进程的创建

    朱荟潼 + 原创作品转载请注明出处 + <Linux内核分析>MOOC课http://mooc.study.163.com/course/USTC 1000029000 第六周 进程的描述 ...

  6. 20135320赵瀚青LINUX第三章读书笔记

    第三章 进程管理 3.1 进程 进程的定义: 是处于执行期的程序以及它所包含的资源的总称. 线程的定义: 是在进程中活动的对象. 每个线程都拥有一个独立的程序计数器.进程栈和一组进程寄存器. 内核调度 ...

  7. 2013337朱荟潼 Linux&深入理解计算机系统第七章读书笔记——链接

    第七章--链接 0.总结 链接编译时可以采用静态链接或动态链接. 连接器主要任务:符号解析和重定位. 多个目标文件可定义相同的符号,可以被连接到一个单独的静态库. 链接器可以生成部分链接的可执行文件 ...

  8. 2013337朱荟潼 Linux第一章读书笔记——Linux内核简介

    一.Unix历史 二.Linux足迹 类Linux系统.非商业化产品.用途广泛 三.操作系统和Linux内核简介 1.操作系统 (1)是指在整个最基本功能系统中负责完成最基本功能和系统管理的部分. ( ...

  9. 2013337朱荟潼 Linux第二章读书笔记——从内核出发

    1.获取内核源码 1.1Git 分布式的:下载和管理Linux内核源代码: - 获取最新提交到版本树的一个副本 $ git clone git://git.kernel.org/pub/scm/lin ...

随机推荐

  1. 【Alpha Go】Day 1 !

    [Alpha Go]Day 1 ! Part 0 · 简要目录 Part 1 · 任务分配 Part 2 · 他日安排 Part 3 · 预期任务量 Part 4 · 团队贡献值计算原则 Part 1 ...

  2. 团队作业——Beta冲刺1

    团队作业--Beta冲刺 冲刺任务安排 杨光海天 今日任务:开会讨论下,Beta阶段主要的冲刺内容 明日任务:根据冲刺内容,具体分配个人任务,对于冲刺内容做准备 吴松青 今日任务:跟新组员熟悉下,联络 ...

  3. React-Native开发笔记 持续更新

    1.css单位转换px2dp 在做页面开发的时候习惯了用rem去做css单位,处理各种尺寸数据,到了React-Native里面做app开发时,rem就不好用了,这个时候就需要转换成另外一个单位,基本 ...

  4. Python shutil.md

    shutil shutil模块包括高级文件操作,例如复制和归档. Copying Files shutil.copyfileobj(fsrc, fdst[, length]):将类似文件的对象fsrc ...

  5. linux(centos 7) 下安装nodejs

    1,到node官网下载linux版本,有32和64位版本 2,将文件上传到linux下 3,使用tar -xvf node-v8.9.3-linux-x64.tar.xz 进行解压 4,建立软连接,变 ...

  6. JVM内存管理及GC机制

    一.概述 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾清理代码,对内存泄露 ...

  7. Python2.7-zipfile

    zipfile模块,提供了基本操作后缀为“zip”的文件的接口,一般使用 ZipFile 类完成操作 1.模块方法 zipfile.is_zipfile(filename):判断 filename 是 ...

  8. day 27

    今日内容: 关于面向对象的一些内置方法 1.__str__:在对象被打印时自动触发,可用来定义对象被打印. 注意:返回必须是一个字符串类型的值 ############################ ...

  9. day11有参装饰器,无参装饰器

    今日内容 1.有参装饰器 2.无参装饰器 什么是装饰器? 用来为被装饰对象添加新功能的工具. 注:装饰器可以是任意可调用对象,被装饰对象也可以是任意可调用对象. 为何要用装饰器? 开放封闭原则:对修改 ...

  10. 第4章 初识STM32

    第4章     初识STM32 全套200集视频教程和1000页PDF教程请到秉火论坛下载:www.firebbs.cn 野火视频教程优酷观看网址:http://i.youku.com/firege ...