From 1623eb2746bf7e6e886f2a5ad0f07138dfb3e08b Mon Sep 17 00:00:00 2001 From: gatieme Date: Thu, 19 May 2016 19:38:21 +0800 Subject: [PATCH] ... --- study/kernel/process/README.md | 27 +++ .../process/create/01-duplicate/README.md | 166 ++++-------------- 2 files changed, 57 insertions(+), 136 deletions(-) create mode 100644 study/kernel/process/README.md diff --git a/study/kernel/process/README.md b/study/kernel/process/README.md new file mode 100644 index 0000000..b406d7b --- /dev/null +++ b/study/kernel/process/README.md @@ -0,0 +1,27 @@ +Linux进程管理与调度-之-目录总结 +======= + + +| 日期 | 内核版本 | 架构| 作者 | GitHub| CSDN | +| ------------- |:-------------:|:-------------:|:-------------:|:-------------:|:-------------:| +| 2016-05-12 | [Linux-4.5](http://lxr.free-electrons.com/source/?v=4.5) | X86 & arm | [gatieme](http://blog.csdn.net/gatieme) | [LinuxDeviceDrivers](https://github.com/gatieme/LDD-LinuxDeviceDrivers) | [Linux进程管理与调度](http://blog.csdn.net/gatieme/article/category/6225543) | + + +#进程的描述 +------- +| CSDN | GitHub | +| ------------- |:-------------:| +| [Linux进程描述符task_struct结构体详解--Linux进程的管理与调度(一)](http://blog.csdn.net/gatieme/article/details/51383272)| [study/kernel/process/task/01-task_struct](https://github.com/gatieme/LDD-LinuxDeviceDrivers/tree/master/study/kernel/process/task/01-task_struct) | +|[ Linux的命名空间详解--Linux进程的管理与调度(二)](http://blog.csdn.net/gatieme/article/details/51383322) | [study/kernel/process/task/02-namespace/](https://github.com/gatieme/LDD-LinuxDeviceDrivers/tree/master/study/kernel/process/task/02-namespace) | +|[Linux进程ID号--Linux进程的管理与调度(三)](http://blog.csdn.net/gatieme/article/details/51383377) | [study/kernel/process/task/03-pid](https://github.com/gatieme/LDD-LinuxDeviceDrivers/tree/master/study/kernel/process/task/03-pid)| + + +#进程的创建 +------- + +| CSDN | GitHub | +| ------------- |:-------------:| +| [Linux内核线程、轻量级进程和用户进程以及其创建方式]()| [study/kernel/process/create/01-duplicate/](https://github.com/gatieme/LDD-LinuxDeviceDrivers/tree/master/study/kernel/process/create/01-duplicate)| + +#进程的调度 +------- \ No newline at end of file diff --git a/study/kernel/process/create/01-duplicate/README.md b/study/kernel/process/create/01-duplicate/README.md index 14b589f..0ddc6f1 100644 --- a/study/kernel/process/create/01-duplicate/README.md +++ b/study/kernel/process/create/01-duplicate/README.md @@ -1,4 +1,4 @@ -Linux下进程的创建过程 +Linux内核线程、轻量级进程和用户进程以及其创建方式 ======= @@ -9,68 +9,65 @@ Linux下进程的创建过程 | ------------- |:-------------:|:-------------:|:-------------:|:-------------:|:-------------:| | 2016-05-12 | [Linux-4.5](http://lxr.free-electrons.com/source/?v=4.5) | X86 & arm | [gatieme](http://blog.csdn.net/gatieme) | [LinuxDeviceDrivers](https://github.com/gatieme/LDD-LinuxDeviceDrivers) | [Linux进程管理与调度-之-进程的创建](http://blog.csdn.net/gatieme/article/category/6225543) | +#Linux进程类别 +------- +虽然我们在区分Linux进程, 但是我还是想说Linux下只有一种类型的进程,那就是task_struct, 当然我也想说Linux下其实本质上没有线程的概念, 线程其实上是 + +##Linux下进程和线程的区别 + +而由于其运行空间的不同,从而演变出内核线程 + +##内核线程 +------- + +内核线程只运行在内核态,不受用户态上下文的拖累。 +处理器竞争:可以在全系统范围内竞争处理器资源; +使用资源:唯一使用的资源是内核栈和上下文切换时保持寄存器的空间 +调度:调度的开销可能和进程自身差不多昂贵 +同步效率:资源的同步和数据共享比整个进程的数据同步和共享要低一些。 +##轻量级进程 +------- - -http://www.linuxidc.com/Linux/2013-07/87011.htm -http://www.linuxeye.com/Linux/1827.html -http://bbs.csdn.net/topics/390872515 -http://blog.csdn.net/yjzl1911/article/details/5613569 -http://blog.csdn.net/dagouaofei/article/details/5644119 -http://blog.chinaunix.net/uid-23769728-id-3129443.html -http://baike.baidu.com/link?url=sCsQDvMUaAikV5W_eKrEL3RVijNHJtOJk8nsCnjlxtnU7yoJ9svp6cwaerQ6Dqc0I-kdoAYrOtMcocCUnzyggK - -http://blog.chinaunix.net/uid-21718047-id-3070635.html - -http://blog.163.com/boneshunter_1234/blog/static/340762320084472122207/ - -http://blog.sina.com.cn/s/blog_626aed8b0100hws6.html - - +轻量级进程(LWP)是建立在内核之上并由内核支持的用户线程,它是内核线程的高度抽象,每一个轻量级进程都与一个特定的内核线程关联。内核线程只能由内核管理并像普通进程一样被调度。 +轻量级进程由clone()系统调用创建,参数是CLONE_VM,即与父进程是共享进程地址空间和系统资源。 +与普通进程区别:LWP只有一个最小的执行上下文和调度程序所需的统计信息。 +处理器竞争:因与特定内核线程关联,因此可以在全系统范围内竞争处理器资源 +使用资源:与父进程共享进程地址空间 +调度:像普通进程一样调度 +用户线程 +用户线程是完全建立在用户空间的线程库,用户线程的创建、调度、同步和销毁全又库函数在用户空间完成,不需要内核的帮助。因此这种线程是极其低消耗和高效的。 +处理器竞争:单纯的用户线程是建立在用户空间,其对内核是透明的,因此其所属进程单独参与处理器的竞争,而进程的所有线程参与竞争该进程的资源。 +使用资源:与所属进程共享进程地址空间和系统资源。 +调度:由在用户空间实现的线程库,在所属进程内进行调度 #Linux下进程的创建流程 - ------- ##进程的复制fork和加载execve - ------- - - 我们在Linux下进行进行编程,往往都是通过fork出来一个新的程序,fork从化字面意义上理解就是说"分叉", 这其实就意味着我们的fork进程并不是真正从无到有被创建出来的。 - - - 一个进程,包括代码、数据和分配给进程的资源,它其实是从现有的进程(父进程)复制出的一个副本(子进程),fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,然后如果我们通过execve为子进程加载新的应用程序后,那么新的进程将开始执行新的应用 - 简单来说,新的进程是通过fork和execve创建的,首先通过fork从父进程分叉出一个基本一致的副本,然后通过execve来加载新的应用程序镜像 * fork生成当前进程的的一个相同副本,该副本成为子进程 - - > 原进程(父进程)的所有资源都以适当的方法复制给新的进程(子进程)。因此该系统调用之后,原来的进程就有了两个独立的实例,这两个实例的联系包括:同一组打开文件, 同样的工作目录, 进程虚拟空间(内存)中同样的数据(当然两个进程各有一份副本, 也就是说他们的虚拟地址相同, 但是所对应的物理地址不同)等等。 - - * execve从一个可执行的二进制程序镜像加载应用程序, 来代替当前运行的进程 - - > 换句话说, 加载了一个新的应用程序。因此execv并不是创建新进程 - - 所以我们在linux要创建一个应用程序的时候,其实执行的操作就是 @@ -130,106 +127,3 @@ do_wp_page()会对这块导致写入异常中断的物理页面进行取消共 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值(比如PID)不同。相当于克隆了一个自己。 - - - - - -#0号进程与1号进程 - -------- - - - -前面我们了解到linux下的进程创建式通过父进程复制自身分叉出的一个副本, 那么我们的系统中就必然存在一个进程是所有进程的祖先,要不然我们从哪里fork分叉出一个个子进程呢,linux下这个进程就是init进程 - - - -但是问题也来了,我们的祖先进程init进程,是从哪里来的? - - - -他总不能也是被分叉来的吧? - - - -如果是,那么分叉它的进程是谁,那么它为什么没有成为祖先进程 - - - -如果不是, 那么好了, 它是怎么创建出来的(真正的从无到有) - - - - - - - -Linux下有两个特殊的进程,idel进程($PID = 0$)和init进程($PID = 1$) - - - - - -* idel进程由系统自动创建, 运行在内核态 - - - - idle进程其pid=0,其前身是系统创建的第一个进程,也是唯一一个没有通过fork()产生的进程。完成加载系统后,演变为进程调度、交换 - - - - - -* init进程由idel创建, - - - - 由0进程创建,完成系统的初始化. 是系统中所有其它用户进程的祖先进程 - - Linux中的所有进程都是有init进程创建并运行的。首先Linux内核启动,然后在用户空间中启动init进程,再启动其他系统进程。在系统启动完成完成后,init将变为守护进程监视系统其他进程。 - - - - - - - - - -系统允许一个进程创建新进程,新进程即为子进程,子进程还可以创建新的子进程,形成进程树结构模型。整个linux系统的所有进程也是一个树形结构。**树根是系统自动构造的(或者说是由内核黑客手动创建的)**,即在内核态下执行的0号进程,它是所有进程的远古先祖。 - - - -由0号进程创建1号进程(内核态),1号负责执行内核的部分初始化工作及进行系统配置,并创建若干个用于高速缓存和虚拟主存管理的内核线程。随后,1号进程调用execve()运行可执行程序init,并演变成用户态1号进程,即init进程。它按照配置文件/etc/initab的要求,完成系统启动工作,创建编号为1号、2号...的若干终端注册进程getty。 - - - -每个getty进程设置其进程组标识号,并监视配置到系统终端的接口线路。当检测到来自终端的连接信号时,getty进程将通过函数execve()执行注册程序login,此时用户就可输入注册名和密码进入登录过程,如果成功,由login程序再通过函数execv()执行shell,该shell进程接收getty进程的pid,取代原来的getty进程。再由shell直接或间接地产生其他进程。 - - - - - -上述过程可描述为:0号进程->1号内核进程->1号用户进程(init进程)->getty进程->shell进程 - - - -注意,上述过程描述中提到:1号内核进程调用执行init函数并演变成1号用户态进程(init进程),这里前者是init是函数,后者是进程。两者容易混淆,区别如下: - - - -1. init()函数在内核态运行,是内核代码 - - - -2. init进程是内核启动并运行的第一个用户进程,运行在用户态下。 - - - -3. 一号内核进程调用execve()从文件/etc/inittab中加载可执行程序init并执行,这个过程并没有使用调用do_fork(),因此两个进程都是1号进程。 - - - - -