线程与进程
进程:资源分配的最小单元,程序在操作系统中运行的实例
线程:系统调度的最小单元
解释:操作系统为每个程序实例——即进程分配资源(虚拟内存/虚拟地址空间);
一个进程内可以包含多个线程,这些线程共享进程的资源(代码,数据),同时拥有独有的部分资源(独立的栈指针、寄存器组值)以保证线程独立性;
CPU核心在同一时刻只能运行一个线程,也因此可以访问该线程所属进程的虚拟内存空间;
虚拟内存空间、内核空间和用户空间
Linux虚拟内存的大小为(在32位的x86机器上),内核将这4G字节的空间分为两部分。最高的1G字节(从虚地址0xC0000000到0xFFFFFFFF)供内核使用,称为“内核空间”。而较低的3G字节(从虚地址0x00000000 到0xBFFFFFFF),供各个进程使用,称为“用户空间”。每个进程可以通过系统调用进入内核(内核模式)。Linux内核空间由系统内的所有进程共享。于是,从具体进程的角度来看,每个进程可以拥有4G字节的虚拟地址空间(也叫虚拟内存)。
每个进程有各自的私有用户空间(0~3G),这个空间对系统中的其他进程是不可见的。最高的1GB内核空间则为所有进程以及内核所共享。
用户空间不是进程共享的,而是进程隔离的。每个进程最大都可以有3GB的用户空间。一个进程对其中一个地址的访问,与其它进程对于同一地址的访问不冲突。任意一个时刻,在一个CPU上只有一个进程中的一个线程在运行。所以对于此CPU来讲,在这一时刻,整个系统只存在一个4GB的虚拟地址空间,这个虚拟地址空间是面向此进程的。当进程发生切换的时候,虚拟地址空间也随着切换。由此可以看出,每个进程都有自己的虚拟地址空间,只有此进程运行的时候,其虚拟地址空间才被运行它的CPU所知。在其它时刻,其虚拟地址空间对于CPU来说,是不可知的。所以尽管每个进程都可以有4 GB的虚拟地址空间,但在CPU眼中,只有一个虚拟地址空间存在。虚拟地址空间的变化,随着进程切换而变化。
从上面我们知道,一个程序编译连接后形成的地址空间是一个虚拟地址空间,但是程序最终还是要运行在物理内存中。因此,应用程序所给出的任何虚地址最终必须被转化为物理地址,所以,虚拟地址空间必须被映射到物理内存空间中,这个映射关系需要通过硬件体系结构所规定的数据结构来建立。这就是我们所说的段描述符表和页表,Linux主要通过页表来进行映射。
于是,我们得出一个结论,如果给出的页表不同,那么CPU将某一虚拟地址空间中的地址转化成的物理地址就会不同。所以我们为每一个进程都建立其页表,将每个进程的虚拟地址空间根据自己的需要映射到物理地址空间上。既然某一时刻在某一CPU上只能有一个进程在运行,那么当进程发生切换的时候,将页表也更换为相应进程的页表,这就可以实现每个进程都有自己的虚拟地址空间而互不影响。
线程切换和进程切换
由上可知,对于同一进程内的线程切换,只需要切换所谓的线程上下文(寄存器上下文,包括通用寄存器、PC指针(EIP)、处理器状态寄存器(EFLAGS)、栈指针(ESP));而对于不同进程内的两个线程切换会引起进程切换,需要切换切换进程上下文,这就是线程切换耗时远低于进程切换的原因
进程上下文可以分为三个部分:用户级上下文、寄存器上下文以及系统级上下文。
用户级上下文: 正文、数据、用户堆栈以及共享存储区;
寄存器上下文: 通用寄存器、程序寄存器(IP)、处理器状态寄存器(EFLAGS)、栈指针(ESP);
系统级上下文: 进程控制块task_struct、内存管理信息(mm_struct、vm_area_struct、pgd、pte)、内核栈
对于用户级和系统级上下文的切换涉及到虚拟地址空间的切换,前面提到虚拟地址空间是由物理内存空间映射得到,因此修改这个映射关系即可改变虚拟地址空间的切换。Linux通过修改
引起线程切换的因素
当前执行任务(线程)的时间片用完之后,系统CPU正常调度下一个任务
中断处理,在中断处理中,其他程序”打断”了当前正在运行的程序。当CPU接收到中断请求时,会在正在运行的程序和发起中断请求的程序之间进行一次上下文切换。中断分为硬件中断和软件中断,软件中断包括因为IO阻塞、未抢到资源或者用户代码等原因,线程被挂起。
用户模式切换,对于一些操作系统,当进行用户模式切换时也会进行一次上下文切换,虽然这不是必须的。
多个任务抢占锁资源,在多任务处理中,CPU会在不同程序之间来回切换,每个程序都有相应的处理时间片,CPU在两个时间片的间隔中进行上下文切换
用户模式和内核模式
为了使操作系用内核提供一个无懈可击的进程抽象,处理器必须提供一种机制,限制一个应用可以执行的指令以及它可以访问的地址空间范围。
处理器通常是用某个控制寄存器中的一个模式位来提供这种功能的,该寄存器描述了进程当前享有的特权。
当设置了模式位时,进程就运行在内核模式中,即超级用户模式。
一个运行在内核模式的进程可以执行指令集中的任何指令,并且可以访问系统中任何存储器位置。
没有设置模式位时,进程就运行在用户模式中。用户模式中的进程不允许执行特权指令,比如停止处理器,改变模式位,或者发起一个I/O操作。也不允许用户模式中的进程直接引用地址空间中内核区内的代码和数据。
运行应用程序代码的进程初始时是在用户模式中的。
进程从用户模式变为内核模式的唯一方法是通过诸如中断,故障或者陷入系统调用这样的异常,当异常发生时,控制传递到异常处理程序,处理器将模式从用户模式变为内核模式。
处理程序运行在内核模式中,当他返回到应用程序代码时,处理器就把模式从内核模式改回到用户模式。
参考
Linux下的进程1——进程概念,进程切换,上下文切换,虚拟地址空间_lixungogogo的博客-CSDN博客_进程的上下文