第三章 进程管理

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, &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 写时拷贝

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第三章读书笔记的更多相关文章

  1. 20135320赵瀚青LINUX第五章读书笔记

    第五章--系统调用 5.1 与内核通信 作用 1.为用户空间提供一种硬件的抽象接口 2.保证系统稳定和安全 3.除异常和陷入,是内核唯一的合法入口. API.POSIX和C库 关于Unix接口设计:提 ...

  2. 20135320赵瀚青LINUX第四章读书笔记

    概述 什么是进程调度 进程调度:在可运行态进程之间分配有限处理器时间资源的内核子系统. 一.调度策略 4.1进程类型 I/O消耗型进程:大部分时间用来提交I/O请求或是等待I/O请求,经常处于可运行状 ...

  3. 20135320赵瀚青LINUX第十八章读书笔记

    概述:调试工作艰难是内核级开发区别于用户级开发的一个显著特点 18.1准备开始 内核调试往往是一个令人挠头不已的漫长过程.幸运的是,在这些费劲的问题中也有不少比较简单而且容易消灭的小bug,运气好你可 ...

  4. 20135320赵瀚青LINUX第五周学习笔记

    赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 按照刘老师的周从三个角 ...

  5. 20135320赵瀚青LINUX第六周学习笔记

    赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 这周主要讲解的是进程. ...

  6. 20135320赵瀚青LINUX第八周学习笔记

    赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 本周学习的是linux ...

  7. 20135320赵瀚青LINUX第七周学习笔记

    赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 本周学习的内容主要是讨 ...

  8. 三20135320赵瀚青LINUX内核分析第二周学习笔记

    赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 一.计算机的三个法宝 存储程 ...

  9. 20135320赵瀚青LINUX内核分析第三周学习笔记

    赵瀚青原创作品转载请注明出处<Linux内核分析>MOOC课程http://mooc.study.163.com/course/USTC-1000029000 概述 本周是学习的主要是构造 ...

随机推荐

  1. ZOJ 3932 Deque and Balls

    There are n balls, where the i-th ball is labeled as pi. You are going to put n balls into a deque. ...

  2. R语言中基于聚类的离群点挖掘

    思路:首先,通过K-means算法将数据点划分为成若K个簇:然后计算每一个数据对象到最近簇的中心距离,来与离群点设置的阈值进行比较,以此来判别该数据对象是否是离群点. 1.读取数据 data<- ...

  3. ORACLE内存结构之SGA

    SGA的管理: SQL> show parameter sga NAME                                 TYPE        VALUE ---------- ...

  4. 多线程入门-第六章-线程的调度与控制之join

    /* 线程合并:将指定的线程加入到当前线程,可以将两个交替执行的线程合并为顺序执行的线程,即单线程. 如在B线程中调用了A的join方法,则线程A执行完后,才会执行线程B. */ public cla ...

  5. 网络编程 - 1.简单的套接字通信/2.加上通信循环/3.bug修复/4.加上链接循环/5.模拟ssh远程执行命令

    1.简单的套接字通信 服务端 ''' 服务端 接电话 客户端 打电话 1.先启动服务端 2.服务端有两种套接字 1.phone 用来干接收链接的 2.conn 用来干收发消息的 ''' import ...

  6. 分类,logistic回归

    1. 使用回归进行分类 机器学习中分类是指输入一个样本点,输出这个样本点所属的类别,预测的是一个离散值,如类别(1,2). 而回归问题是输入一个样本点,预测一个值,这个值是连续值,可以介于\([1,2 ...

  7. Linux进入-adsdfsd目录

    Linux进入-adsdfsd目录 如果某个目录名称是短线(短横线)开头的 要想在命令行中进入目录,使用如下命令: cd -- -adsdfsd 延伸: 其他非寻常操作: http://www.cnb ...

  8. (0.2.5)Mysql安装——RPM方式安装

    rpm安装mysql 卸载与安装服务端   一.安装服务端与客户端 #查看RPM包中所有的文件shell> rpm -qpl mysql-community-server-version-dis ...

  9. python web框架 django 练习1 django 1.11版本

    django练习 在我自己项目里创建一个xiaoliu的文件夹 里面创建s1.py 文件 s1.py文件 里面写各种函数 from django.shortcuts import HttpRespon ...

  10. 程序猿Web面试之jQuery

    版权声明:本文为博主原创文章,未经博主同意不得转载. https://blog.csdn.net/powertoolsteam/article/details/32325013  又到了一年一度的 ...