20135320赵瀚青LINUX第三章读书笔记
第三章 进程管理
3.1 进程
进程的定义:
是处于执行期的程序以及它所包含的资源的总称。
线程的定义:
是在进程中活动的对象。
每个线程都拥有一个独立的程序计数器、进程栈和一组进程寄存器。
内核调度的对象是线程,而不是进程。
3.2 进程描述符及任务结构
进程描述符的结构:task_struct,定义在<linux/sched.h>中,包含一个具体进程的所有信息。
task_struct 就是指 PCB (进程控制块)。
3.2.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 进程上下文
内核“代表进程执行”并处于进程上下文中。
此上下文中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, ¤t->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 写时拷贝
fork() 和 exec()
fork():通过拷贝当前进程创建一个子进程。
exec():负责读取可执行文件并将其载入地址空间开始运行。
3.3.2 fork()
通过clone()系统调用实现fork()。
do_fork完成创建中大量工作,定义在kernel/fork.c文件中。
调用copy_process()函数让进程开始运行。(具体工作很有意思详见《Linux内核设计与实现》第27页)
3.3.3 vfork()
与fork()很类似。
实现是通过向clone()系统调用传递一个特殊标志来进行。(具体工作很有意思详见《Linux内核设计与实现》第28页)
3.4 线程在Linux中的实现
3.4.1 创建线程
在调用clone()需传递一些参数标志指明共享资源。
clone(CLONE_VM | CLONE_FS | CLONE_SIGHAND, 0);
新建的进程和他的父进程就是线程。
一个普通的fork()。
clone(SIGHAND, 0);
vfork()的实现。
clone(CLONE_VFORK | CLONE_VM | SIGHAND, 0);
clone()参数标志决定新创建进程的行为方式和父子进程之间共享的资源种类。(具体参数标识详见《Linux内核设计与实现》第29-30页)
3.4.2 内核线程
内核线程只能由其他内核线程创建。
内核通过从kthreadd内核进程中衍生出所有新内核线程来自动处理。
在<linux/kthread.h>中声明接口。
新的任务是由kthread内核进系统调用程通过clone()而创建的。
内核线程启动后一直运行知道调用do_exit()退出,或者内核其它部分调用kthread_stop()退出。
3.5 进程终结
进程的退出一般是显示或隐式地调用了exit(),或者接受了某种信号。
只要退出,最终都调用了do_exit()(具体完成的繁琐工作详见《Linux内核设计与实现》第31页)。
3.5.1 删除进程描述符
wait()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果执行成功则返回子进程识别码(PID),如果有错误发生则返回-1。
最终需要释放进程描述符时,release_task()会被调用(具体需要完成的工作详见《Linux内核设计与实现》第32页)
3.5.2 孤儿进程造成的进退维谷
如果父进程在子进程之前退出,必须有机制来保证子进程能找到一个新的父亲,否则这些成为孤儿的进程就会在退出时永远处于僵死状态。
解决方法是给子进程在当前线程组内找一个线程作为父亲,如果不行,就让init做它们的父进程。在do_exit()中会调用exit_notify(),该函数会调用forget_original_parent(),而后者会调用find_new_reaper()来执行寻父。
遍历了两个链表:子进程链表和ptrace子进程链表,给每个子进程设置新的父进程。
20135320赵瀚青LINUX第三章读书笔记的更多相关文章
- 20135320赵瀚青LINUX第五章读书笔记
第五章--系统调用 5.1 与内核通信 作用 1.为用户空间提供一种硬件的抽象接口 2.保证系统稳定和安全 3.除异常和陷入,是内核唯一的合法入口. API.POSIX和C库 关于Unix接口设计:提 ...
- 20135320赵瀚青LINUX第四章读书笔记
概述 什么是进程调度 进程调度:在可运行态进程之间分配有限处理器时间资源的内核子系统. 一.调度策略 4.1进程类型 I/O消耗型进程:大部分时间用来提交I/O请求或是等待I/O请求,经常处于可运行状 ...
- 20135320赵瀚青LINUX第十八章读书笔记
概述:调试工作艰难是内核级开发区别于用户级开发的一个显著特点 18.1准备开始 内核调试往往是一个令人挠头不已的漫长过程.幸运的是,在这些费劲的问题中也有不少比较简单而且容易消灭的小bug,运气好你可 ...
- 20135320赵瀚青LINUX第五周学习笔记
赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 按照刘老师的周从三个角 ...
- 20135320赵瀚青LINUX第六周学习笔记
赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 这周主要讲解的是进程. ...
- 20135320赵瀚青LINUX第八周学习笔记
赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 本周学习的是linux ...
- 20135320赵瀚青LINUX第七周学习笔记
赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 本周学习的内容主要是讨 ...
- 三20135320赵瀚青LINUX内核分析第二周学习笔记
赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.计算机的三个法宝 存储程 ...
- 20135320赵瀚青LINUX内核分析第三周学习笔记
赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 本周是学习的主要是构造 ...
随机推荐
- JAVA NIO使用非阻塞模式实现高并发服务器
参考:http://blog.csdn.net/zmx729618/article/details/51860699 https://zhuanlan.zhihu.com/p/23488863 ht ...
- 170428、centos6.5安装Subversion + Apache +Jsvnadmin
服务器地址:192.168.0.112 root用户操作 建议 安装前 更 新操作系统 # yum update 更新完成后重启 # reboot 安装 装 apache # yum install ...
- [LeetCode] 1.Two Sum - Swift
1. Two Sum Given an array of integers, return indices of the two numbers such that they add up to a ...
- Linux系统CPU核数等信息查看
版权声明:本文为原创文章,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明. https://blog.csdn.net/fgf00/article/details/52584 ...
- PHP Ajax跨域解决
PHP Ajax 跨域问题最佳解决方案 本文通过设置Access-Control-Allow-Origin来实现跨域. 例如:客户端的域名是client.runoob.com,而请求的域名是serve ...
- 排序算法review<2>--Shell 排序
shell排序方法也是一种插入排序算法,于1959年由D.L.Shell提出,其基本方法是:首先将带排序文件分为d1(d1<n)组,将所有彼此之间间隔为d和d的倍数的记录放在一组中,然后在组内进 ...
- 使用arc进行code review
https://secure.phabricator.com/book/phabricator/article/arcanist_quick_start/ 使用流程: 流程 本部分来自arcanist ...
- Redis常见操作
1. 对于key的所有操作 del key1 key2 … keyn 作用:删除1个或者多个键返回值:不存在的key忽略掉,返回真正删除的key的数量 rename key newkey 作用:给ke ...
- Spring Bean声明周期
Bean的生命周期 理解Spring Bean的生命周期很容易.当一个bean被实例化时,它可能需要执行一些初始化使它转换成可用状态.同样,当bean不再需要,并且从容器中移除时,可能需要做一些清除工 ...
- python和shell之间变量的相互调用
python -> shell: 1.环境变量 2.字符串连接 3.通过管道 import os var=’123’ os.popen(’wc -c’, ’w’).write(var) 4.通过 ...