内核空间与用户空间,进程与线程以及上下文

个人理解,比较啰嗦,逻辑性也不强。如果有疑问可以讨论,或者有大佬提点也是可以的。

最近在学习Linux,提到了内核空间与用户空间还有上下文切换,个人很有兴趣但是这几个概念太过抽象很难理解,所以找了一些资料整理一下谈谈自己的理解。个人浅见不涉及太多底层原理,大佬见笑。

  1. 内核空间与用户空间

首先看一下我从网上找到的关于内核空间和用户空间的解释(来源:https://blog.csdn.net/xiaoaid01/article/details/51659037):

现在操作系统都是采用虚拟存储器,那么对32位操作系统而言,它的寻址空间(虚拟存储空间)为4G(2的32次方)。操心系统的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的所有权限。为了保证用户进程不能直接操作内核,保证内核的安全,操心系统将虚拟空间划分为两部分,一部分为内核空间,一部分为用户空间。针对linux操作系统而言,将最高的1G字节(从虚拟地址0xC0000000到0xFFFFFFFF),供内核使用,称为内核空间,而将较低的3G字节(从虚拟地址0x00000000到0xBFFFFFFF),供各个进程使用,称为用户空间。每个进程可以通过系统调用进入内核,因此,Linux内核由系统内的所有进程共享。于是,从具体进程的角度来看,每个进程可以拥有4G字节的虚拟空间。空间分配如下图:1

有些看不太懂哈,不过我们可以简化提炼一下。简单来说,这是操作系统的一种安全机制。内核是操作系统的核心,拥有整个操作系统最高的权限,可以访问所有的硬件。(或者可以理解为内核有控制和分配所有硬件资源的权限)但是,对于普通应用程序来说,这是不必要的,也是不安全的。所以,为了保证内核的安全以及对硬件权限的控制,系统将普通用户和内核进行隔离划分出独立的运行空间,也即是用户空间和内核空间。如此可以把Linux系统的机构抽象为硬件>内核空间>用户空间。如下图:

ll

举个例子,你(用户)有一家工厂,但是你并不知道怎么操作工厂里的设备进行生产(计算机运行基于二进制,并不能被直接操作),所以你需要人来进行管理(内核)以及生产(应用程序),其中管理拥有着最大的权力可以控制所有的设备(硬件),出于安全考虑管理和工人的工作区域是完全隔离的(也就是内核空间和用户空间)。

  1. 系统调用、API、库、内核态、用户态

还是以上的例子,工厂和工人都有了,可以开工了。工人A(应用)说他要去仓库(硬盘)拿一些材料用来加工,但是他并没有权限,所以,此时A去请求管理员,管理员把A需要的东西拿过来。这其中A的请求就叫做系统调用。后来又来了许多工人,他们的能力虽然不完全相同,但有些工具却都需要,于是工厂将这些工具提前准备好公用(这就是库),工人只需要到特定的位置(API)就可以使用这些工具。

由于某些功能在不同的应用程序中会经常使用,所以为了避免浪费,将这些常用的功能事先编写打包起来并且留下访问的接口之后就是库,不同的应用在使用这些功能的时候只需要通过事先留下的接口就可以使用这些功能,避免了重复开发浪费资源。这些接口就是API。还是用上面的例子解释,工人A在完成一件事情的过程中出现了两种状态,一种是在自己的独立空间工作,一种是把必须由内核操作的部分交由内核执行,这两种状态分别对应的就是用户态和内核态。需要注意的是这种状态是针对进程也就是工人A在进行的事情的描述。

  1. 进程、线程、上下文

我们都知道现在的操作系统都是多任务操作系统,但实际上对于单核心CPU来说,它在某个具体时间只能同时处理一个任务,而多任务的实现,很重要的就是进程的出现。由于在单线程阶段CPU只能处理一个任务经常会导致CPU处于空闲状态而浪费大量资源。进程出现后让计算机的性能得到了很大的提升,但是后来人们发现CPU会顺序处理进程中的每个任务,当一个进程有多个子任务的时候,顺序执行带来的效率问题就出现了,于是,线程的概念也就出现了。线程把进程的子任务进行分割,每个子任务对应一个线程,这样让进程内部的并发成为了可能。

那么进程线程是如何解决CPU同时只能处理一个任务从而解决多任务的问题的呢。这里谈谈我的理解。

首先,进程的是程序在运行时对应的特定内存空间,每个进程的内存空间相互独立互不干扰,保存着程序运行时每个时刻的状态,为进程切换提供可能。其次,CPU的运行相对于其他的硬件是非常快的,以至于CPU实际上长时间是出于空闲状态的。然后,在CPU开始执行一个程序的时候,与其相关的资源必须已经就位。(比如你去找人办事,办事的时候你得把你办事用的所有东西都准备好)这里除了CPU之外与程序相关的所有资源构成了程序的运行环境,也就是这个程序的上下文。

把这些串起来我们就可以得到下面的信息:我们之前提到CPU同时只能处理一个任务,那当有多个任务同时需要处理怎么办呢?轮着来,也就是如果有A、B两个程序同时运行,在CPU这里实际上是这样的:A→保存A上下文→读取B上下文→B→保存B上下文→读取A上下文→A……如此循环直到程序结束,由于CPU运行极快,我们并不能感知到A和B中间短暂的中止状态,于是在我们看来就像是在同时运行。

那么线程是什么呢,再举个例子,比如程序A在运行的时候有三个子任务A1、A2、A3由于CPU的特性这三个任务会被顺序执行,也就是如果在执行A1的时候我们需要A3的结果单线程的情况下意味着我们只能等待A1、A2、之行结束。这显然不符合我们的要求,于是线程的概念就出现了,线程把每个进程的子任务独立出来单个处理,当CPU在处理程序A的时候CPU的运行时间被分成更细小的片段执行,由于不是等待A1执行完在执行A2而是A1→A2→A3→A1→A2→A3……直到执行结束。如下图:

 

再加一句,CPU在工作的时候是按照时间片段进行的,靠这些分割的时间片段来回切换实现了多任务。所以也有的人会说线程和进程描述的是CPU时间段。

 

(线程把进程的CPU时间继续分割来解决进程的并发问题)

QQ截图20180330085446

 

 

参考:

https://blog.csdn.net/luoweifu/article/details/46595285
https://blog.csdn.net/whl_program/article/details/70217354
https://blog.csdn.net/xiaoaid01/article/details/51659037
https://www.zhihu.com/question/25532384

 

本文来自投稿,不代表Linux运维部落立场,如若转载,请注明出处:http://www.178linux.com/93744

(5)
伪装的萝莉伪装的萝莉
上一篇 2018-03-30
下一篇 2018-03-30

相关推荐

评论列表(1条)

  • 涤生
    涤生 2018-03-31 23:12

    不错,很有理论功底。