理解进程和线程

形象生动的引入话题(非原创)

通俗易懂的进程与线程之间的关系(有图)_常见进程,线程对应的组合关系
具体就是在说,有一座工厂(CPU)时刻在运行,工厂的电力有限,一次只能供给一个车间(进程)使用,一个车间里,可以有很多工人(线程),他们协同完成一个任务。车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的(线程间资源共享)。可是,每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面有人的时候,其他人就不能进去了(一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存)。一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。(互斥锁”(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域)。。。(自己去看,有点意思)

科学的定义

进程(Process)是指一个正在执行的程序实例,拥有独立的地址空间和资源,是操作系统进行资源分配和调度的基本单位。
线程(Thread)是进程内的一个执行单元,它与同一进程内的其他线程共享进程的地址空间和资源。

总而言之:进程=资源+指令,线程=指令,可以看出线程是进程中实施调度和分派的基本单位。

进程线程的内存分配关系

(标黄的是新学的专有名词,由于很多知识都过于零散,就想办法把它们串起来,若有错误请指出,谢谢~)
在这里插入图片描述

  • 首先明确的是这里所说的内存空间是虚拟的(虚拟内存),实际的物理内存由操作系统进行管理和分配。操作系统通过虚拟内存管理机制,将进程的虚拟内存映射到物理内存中。这里的虚拟内存管理机制是通过映射表实现的,映射表记录了虚拟地址和物理地址之间的对应关系,以及一些访问权限等等,操作系统通过映射表实现虚拟地址到物理地址的转换。当进程访问虚拟地址时,操作系统会检查映射表,找到对应的物理地址,然后进行内存访问
    可见,映射表是十分重要的,所以它放在进程的内核虚拟内存中(如图顶部位置),属于用户不可见的内存。进程无法直接访问和修改映射表的内容,只能通过系统调用间接访问(由用户模式切换到内核模式,这个切换也是上下文切换的一部分)
    在这里插入图片描述
  • 然后明确一下线程的内存都在进程的内存中,进程的内存已经如上上图所示了( 具体功能可查),所以这里就来谈论线程的内存分为哪几部分,以及它们分别存放在进程的哪些区域
  1. 栈(Stack):每个线程都有自己的栈空间,用于存储局部变量、函数调用信息以及其他临时数据。线程的栈通常存放在进程的堆栈段(stack segment)中。线程间独立
  2. 堆(Heap):线程可以通过动态内存分配函数(如malloc、new等)来申请堆内存。堆内存是进程共享的,不同线程可以访问和修改堆内存中的数据。堆内存通常存放在进程的堆段(heap segment)中。线程间共享
  3. 全局变量和静态存储区(Global Variables and Static Storage Area):全局变量和静态存储区是在程序运行期间一直存在的内存区域。不同线程可以访问和修改全局变量和静态存储区中的数据。它们通常存放在进程的数据段(data segment)或者BSS段(Block Started by Symbol)中。线程间共享
  4. 代码(Code):线程的执行代码通常存放在进程的代码段(text segment)中。代码段是存储程序执行代码的内存区域,它通常是只读的,用于存放程序的指令。线程间共享

当然线程间还有线程的寄存器(用于保存临时变量和计算结果)、线程局部存储(TLS,虽然也位于主存,但不在进程的地址空间)这三个部分是线程私有的,其他内存资源都是线程间共享的,这样的好处在于:
1、节省内存和提高效率 2、数据一致性 3、简化通信 ,提供便捷协作等等
尽管线程间资源共享有诸多好处,,但也应该合理使用和管理,避免数据竞争和冲突

  • 多说一嘴,当我们fork()一个子进程时,子进程会继承父进程的内存空间的一个副本(当然也有一小点不同的地方,就是①权限调整(比如最上面那张图片的只读代码段,可能被调整为只读和可执行)和②内存映射表的更新),使二者之间相互独立。但是,虽说内存空间一样大,但实际的物理内存可能有所不同,比如说涉及到写时复制技术(COW,Copy-on-write),就是内存页的写时复制(自行查阅,这里不多说)

CPU在多个控制流之间切换的机理

这里的控制流指的是进程或线程。
CPU在多个控制流之间切换的过程主要通过操作系统的调度器(scheduler)来完成的。调度器是操作系统的一部分,负责决定哪个控制流能够占用cpu的时间片,即运行在CPU上执行指令。
当一个控制流需要等待某个事件(如从磁盘到硬盘的数据传输需要大量时间)或者达到了时间片的末尾,操作系统的调度器会进行切换,将CPU的执行权交给另一个控制流。这个过程被称为上下文切换

上下文切换包括以下步骤:

  1. 保存当前控制流的上下文:操作系统会保存当前控制流的寄存器状态、堆栈指针等信息,以便稍后能够恢复执行。
  2. 选择下一个控制流:调度器会根据一定的调度算法(如轮转法、优先级算法等)从就绪队列中选择一个新的控制流。
  3. 恢复下一个控制流的上下文:操作系统会将之前保存的下一个控制流的上下文信息恢复到寄存器中,使得该控制流能够继续执行。
  4. 跳转到下一个控制流的指令:CPU会从恢复的上下文中读取下一个指令,并开始执行该控制流的代码。

这样,CPU就完成了从一个控制流到另一个控制流的切换。

上下文切换包括进程切换、线程切换、异常切换、用户模式切换到内核模式等,不同类型的切换操作具有不同的目的和执行过程,但都涉及保存和恢复上下文信息的过程。

进程切换
进程切换时,需要保存和恢复的上下文信息包括:
①寄存器状态:包括通用寄存器(如eax、ebx、ecx)、指令指针寄存器(如程序计数器PC)、堆栈指针寄存器(如栈指针)等等,这些值并非存入寄存器内存,而是存入主存,和其他各种信息(比如虚拟内存映射、I/O状态等)一起存入进程控制块(PCB)这个数据结构中,每个进程都有一个PCB,PCB通常是在主存上的一块物理内存
【注】保存时,当前进程的状态会从运行态切换为就绪态或阻塞态,这个状态的信息也储存在PCB中;进程恢复时,再传回来
②栈:将一些函数调用过程的局部变量、参数、函数调用返回地址等信息压栈,以便恢复时弹栈。有趣的是栈指针并非存入栈中,而是跑到PCB去了,栈本身的内容就储存在进程的内存空间

线程切换
线程切换和进程切换在某种程度上是相似的,但也是有一些区别的:
①首先,线程切换是在一个进程中进行的,共享一个地址空间,因此不需要像进程一样保存和恢复内存映射关系和页表信息
②进程切换需要保存和恢复进程的文件描述符表,但线程切换不用,因为它们共享同一个文件描述符表
③还有就是资源状态,进程切换需要保存和恢复进程的资源状态,如打开的文件、网络连接等,而线程切换只需要保存和恢复线程的局部状态,不需要处理全局资源状态的切换
④进程有PCB数据结构,线程也有线程控制块(TCB)这一数据结构,它通常是在进程的内存空间中分配的,而不是在进程以外的内存空间。它可能存于进程的栈或堆中,根据操作系统的不同而定

用户模式切换到内核模式:同一个进程中,只涉及到不同权限级别的切换(模式位的设置)

异常切换:好像就是用户模式切换到内核模式也 ̄□ ̄||(给张图缓解尴尬,纸有点皱,字有点丑,见谅见谅)
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值