本文主要涉及操作系统的简介、硬件结构、内存管理、进程管理、文件系统、设备管理等内容,可以作为学习操作系统的辅助文本记录。撰写本文的目的主要是针对操作系统整体做一个相对完整的梳理,以便后续回顾之用。
本文是第三篇,讲述操作系统的进程和线程的基础知识。
第一篇:操作系统(一)基础知识及操作系统启动
第二篇:操作系统(二)内存管理的基础知识
进程的定义: 进程是指一个具有一定独立功能的程序在一个数据集合上的一次动态执行过程。
程序= 文件(静态的可执行文件)
进程 = 执行中的程序 = 程序+执行状态
同一个程序的多次执行过程对应着不同进程,如命令“ls”的多次执行对应多个进程。
进程执行需要的资源:
进程与程序的区别:
进程是动态的,程序是静态的;
程序是有序代码的集合,进程是代码的执行,进程有内核态/用户态;
进程是暂时的,程序是永久的;
进程是一个状态变化的过程,而程序则可以永久保存
进程和程序的组成不同;
进程的组成包括程序、数据和进程控制块。
一个进程的活动期间至少具备三种基本状态:运行状态、就绪状态、阻塞状态,另外还有创建状态和结束状态
运行状态(Running):该时刻进程占用 CPU;
就绪状态(Ready):可运行,由于其他进程处于运行状态而暂时停止运行;
阻塞状态(Blocked):该进程正在等待某一事件发生(如等待输入/输出操作的完成)而暂时停止运行,这时,即使给它CPU控制权,它也无法运行;
创建状态(new):进程正在被创建时的状态;
结束状态(Exit):进程正在从系统中消失时的状态;
如果有大量处于阻塞状态的进程,进程可能会占用大量物理内存空间,被阻塞状态的进程占用着物理内存就一种浪费物理内存的行为。在虚拟内存管理的操作系统中,通常会把阻塞状态的进程的物理内存空间换出到硬盘,等需要再次运行的时候,再从硬盘换入到物理内存。而这些被换出到硬盘的进程,没有占用实际物理内存空间的情况,这个状态就是挂起状态。
另外,挂起状态可以分为两种:
操作系统管理控制进程运行所用的信息集合称为 进程控制块。
操作系统用PCB来描述进程的基本情况以及运行变化的过程。
PCB是进程存在的唯一标志。每个进程都在操作系统中有一个对应的PCB
进程控制块的内容:
PCB通过链表进行组织,通过把具有相同状态的进程组在一起。所有处于就绪状态的进程链在一起,形成 就绪队列; 所有因等待某事件而处于等待状态的进程链在一起,组成 阻塞队列。
什么是上下文切换?
一个进程切换到另一个进程运行,称为进程的上下文切换。暂停当前运行进程,从运行状态变成其他状态;调度另一个进程从就绪状态变为运行状态。
CPU一般是运行多任务的,为了记住每个任务运行到了那里,CPU配备了CPU寄存器和程序计数器。
CPU寄存器是CPU内部一个容量小但速度极快的内存(缓存) (是不是CPU cache?)
程序计数器是用来存储CPU正在执行的指令位置或者即将执行的下一条指令位置。
CPU寄存器和程序计数器是CPU在运行任何任务前所必须依赖的环境,这些环境叫做CPU的 上下文
CPU 上下文切换就是先把前一个任务的 CPU 上下文(CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。
上面所说的任务,主要包括 线程、进程以及中断。
所以,进程的上下文切换不仅包含了虚拟内存、栈、全局变量等用户空间的资源,还包括了内核堆栈、寄存器等内核空间的资源。
Q: 为什么要引入线程?
A: 单进程的实现方式在实现某些问题时会不太好用,比如代码中间需要读一个很大的文件,每次到这里就要耗费事件,影响程序运行,而如果采用多进程并行执行,又要考虑进程的通信和数据共享问题,并且维护进程 的系统开销较大。
线程是进程当中的一条执行流程。
同一个进程内多个线程之间可以共享代码段、数据段、打开的文件等资源,但每个线程各自都有一套独立的寄存器和栈,这样可以确保线程的控制流是相对独立的。
在进程内部增加一类实体,满足以下特性:
这种实体就是线程(Thread)
线程是进程的一部分,描述指令流执行状态,它是进程中的指令执行流的最小单元,是CPU调度的基本单位。
线程的优点:
线程的缺点:
一个线程崩溃,会导致其所属进程的所有线程崩溃;
Q: 为什么?一个线程崩溃,会导致其所属进程的所有线程崩溃;
- 共享资源的破坏: 如果多个线程共享某些资源(如内存、文件句柄等),并且其中一个线程崩溃导致这些共享资源被破坏或异常使用,那么其他线程在访问这些资源时可能会受到影响。这可能导致其他线程出现错误、崩溃或异常行为。
- 异常处理不当: 如果一个线程在发生异常时没有适当地捕获和处理,异常可能会传播到其他线程。在多线程环境下,异常很容易跨越线程边界,并最终导致整个进程中的所有线程崩溃。
- 信号处理: 在某些操作系统中,当一个线程接收到一个致命信号(如段错误)时,整个进程可能会被终止,从而导致所有线程的崩溃。
进程与线程的比较:
进程是资源分配单位,线程是CPU调度单位;
进程拥有一个完整的资源平台,而线程只独享指令流执行的必要资源,如寄存器和栈;
线程具有就绪、等待、运行三种基本状态和状态间的转换关系;
线程能够减少并发执行的时间和空间开销
对于,线程相比进程能减少开销,体现在:
Q: 线程上下文切换的是什么?
这还得看线程是不是属于同一个进程:
- 当两个线程不是属于同一个进程,则切换的过程就跟进程上下文切换一样;
- 当两个线程是属于同一个进程,因为虚拟内存是共享的,所以在切换时,虚拟内存这些资源就保持不动,只需要切换线程的私有数据、寄存器等不共享的数据
用户线程是基于用户态的线程管理库来实现的,那么线程控制块(*Thread Control Block, TCB*) 也是在库里面来实现的,对于操作系统而言是看不到这个 TCB 的,它只能看到整个进程的 PCB。
所以,用户线程的整个线程管理和调度,操作系统是不直接参与的,而是由用户级线程库函数来完成线程的管理,包括线程的创建、终止、同步和调度等
用户线程的优点:
用户线程的缺点:
内核线程是由操作系统管理的,线程对应的 TCB 自然是放在操作系统里的,这样线程的创建、终止和管理都是由操作系统负责。
内核线程的优点:
内核线程的缺点:
轻量级进程(Light-weight process,LWP)是内核支持的用户线程,一个进程可有一个或多个 LWP,每个 LWP 是跟内核线程一对一映射的,也就是 LWP 都是由一个内核线程支持,而且 LWP 是由内核管理并像普通进程一样被调度。
允许进程“加载“一个完成不同的程序,并从main开始执行;
允许进程加载时指定启动参数(argc, argv)
exec调用成功时
代码段、堆栈和堆(heap)等完全重写。
wait()系统调用用于父进程等待子进程的结束;
wait()系统调用的功能
有子进程存活时,父进程进入等待状态等待子进程的返回结果
当某子进程调用exit()时,唤醒父进程,将exit()返回值作为父进程中wait()的返回值
有僵尸子进程等待时,wait()立即返回其中一个值;
无子进程存活时,wait()立刻返回。
进程结束执行时调用exit(),完成进程资源回收;
exit()系统调用的功能
将调用参数作为进程的”结果“
关闭所有打开的文件等占用资源;
释放内存
释放大部分进程相关的内核数据结构;
检查父进程是否是存活着的
如果存货,保留结果的值直到父进程需要它,进入僵尸(zombie/defunct)状态
如果没有,它释放所有的数据结构,进程结束
清理所有等待的僵尸进程
进程终止是最终的垃圾收集(资源回收)
可以让进程在定时器的等待队列中等待指定时间
本节主要操作系统的进程和线程的一些基础知识。
本文参考:
如果您觉得我写的不错,麻烦给我一个免费的赞!如果内容中有错误,也欢迎向我反馈。