3.进程/线程模型

本文详细介绍了进程与线程的基本概念、状态转换、控制机制等内容。解析了进程模型、进程控制块PCB的作用,以及进程与程序的区别。还讨论了线程的引入原因和线程机制的不同实现方式。

3.1进程模型基本概念

多道程序设计:允许多个程序同时进入内存并运行,其目的是为了提高系统效率。

并发环境:一段时间间隔内,单处理器上有两个或两个以上的程序同时处于开始运行但尚未结束的状态,并且次序不是事先确定的。

并发程序:在并发环境中执行的程序。

进程(Process):进程是具有独立功能的程序关于某个数据集合上的一次运行活动,是系统进行资源分配和调度的独立单位,又称任务。   

  1. 进程是程序的一次执行过程;
  2. 进程是正在运行程序的抽象;
  3. 进程将一个CPU变换成多个虚拟的CPU;
  4. 系统资源以进程为单位分配,如内存、文件,每个都有独立的地址空间;
  5. 操作系统将CPU调度给需要的进程。

如何查看有多少个进程在运行:在Windows系统中,可使用任务管理器查看,在linux系统中使用PS命令查看。

进程控制块PCB(Process Control Block):又称进程描述符、进程属性。是操作系统用于管理控制进程的一个专门数据结构,记录进程的各种属性,描述进程的动态变化过程。

PCB是:系统感知进程存在的唯一标志,进程与PCB一一对应。

进程表:所有进程的PCB集合。

PCB内容:

  1. 进程描述信息:a.进程描述信息,唯一,通常是一个整数;b.进程名,通常基于可执行文件名,不唯一;c.用户标识符;d.进程组关系。
  2.  进程控制信息:a.当前状态;b.优先级;c.代码执行入口地址;d.程序的磁盘地址;e.运行统计信息(执行时间、页面调度);f.进程间同步和通信;g.进程的队列指针;h.进程的消息队列指针。
  3. 所拥有的资源和使用情况:a.虚拟地址空间的状况;b.打开文件列表。
  4. CPU现场信息:a.寄存器值(通用寄存器、程序计数器PC、程序状态字PSW、栈指针);b.指向该进程页表的指针。

3.2进程状态及状态转换

进程的三种基本状态:

  1. 运行态:占有CPU,并在CPU上运行;
  2. 就绪态:已经具备运行条件,但由于没有空闲CPU,而暂时不能运行;
  3. 等待态:因等待某一事件而暂时不能运行,例如等待度盘结果。又称为阻塞态、封锁态、睡眠态。

三状态模型转换:

  1. 就绪态——>运行态:调度程序选择一个新的进程运行;
  2. 运行态——>就绪态:运行进程用完了时间片或一个高优先级进程进入就绪状态,抢占正在进行的进程;
  3. 运行态——>等待态:当一个进程等待某个事件发生时,例如请求OS服务、对资源的访问尚不能进行、等待I/O结果、等待另一进程提供信息;
  4. 等待态——>就绪态:所等待的事件发生了。

进程的其他状态:

  1. 创建态:已经完成创建一进程所必要的工作——PID,PCB,但尚未同意执行该进程——因为资源有限;       
  2. 终止态:终止执行后,进程进入该状态,可完成一些数据统计工作,并进行资源回收;
  3. 挂起态:用于调节负载,进程不占用内存空间,其进程映像交换到磁盘上。

进程队列:

  1. 操作系统为每一类进程建立一个或多个队列;
  2. 队列元素为PCB;
  3. 伴随进程状态的改变,其PCB从一个队列进入另一个队列。

3.3进程控制

进程控制操作完成进程各状态之间的转换,由具有特定功能的原语(完成某种特定功能的一段程序,具有不可分割性不可中断性,即原语的执行必须是连续的,在执行过程中不允许被中断)完成:

  1. 进程创建原语 ;
  2. 进程撤消原语;
  3. 阻塞原语;
  4. 唤醒原语;
  5. 挂起原语;
  6. 激活原语;
  7. 改变进程优先级。
  • 进程的创建:
  1. 给新进程分配一个唯一标识以及空的没有用过的进程控制块;
  2. 为新进程分配虚拟地址空间;
  3. 初始化进程控制块:设置默认值(如状态为New..);
  4. 设置相应的队列指针:如,把新进程加到就绪队列链表中。

在UNIX中,使用fork/exec创建进程,Windows中,为Createprocess。

  • 进程的撤销——结束进程
  1. 收回进程所占有的资源:关闭打开的文件,断开网络连接,回收分配的内存;
  2. 撤销该进程的PCB。

在Unix中,使用exit,在Windows中,使用TerminateProcess

  • 进程阻塞:处于运行状态的进程,在其运行过程中期待某一时间发生,如等待键盘输入、等待磁盘数据传输完成、等待其他进程发送消息,当被等待的时间未发生时,由进程自己执行阻塞原语,使自己由运行态变为阻塞态。

在Unix中,使用wait,在Windows中,使用WaitForSingleObject

  • Unix的几个进程控制操作:

    1、fork():通过复制调用进程来建立新的进程,是最基本的进程建立过程

       a.为子进程分配一个空间的进程描述符,即proc结构;

       b.分配给子进程唯一标识pid;

       c.以一次一页的方式复制父进程地址空间(为改善此步骤浪费的时间,linux采用了写时复制技术COW加快创建进程Copy-On-Write);

       d.从父进程处继承共享资源,如打开的文件和当前工作目录等;

       e.将子进程的状态设为就绪,插入到就绪队列;

       f.对子进程返回标识符0;

       g.向父进程返回子进程的pid。

     2、exec():包括一些列系统调用,他们都是通过用一段新的程序代码覆盖原来的地址空间,实现该进程执行代码的转换;

     3、wait():提供初级进程同步操作,能使一个进程等待另一个进程的结束;

     4、exit():用来终止一个进程的运行。

它们都是以系统调用的形式作为一个接口呈现给用户程序,由用户程序调用。

3.4深入理解进程概念

进程的分类:

第一种分类:

  1. 系统进程:为了管理一些资源设置的进程,由于完成关键工作优先级较高。
  2. 用户进程。

第二种分类:

  1. 前台进程:和用户直接交互的一些进程,敲键盘等;
  2. 后台进程:操作系统启动之后创建的一些进程。

第三种分类:

  1. CPU密集型进程;
  2. I/O密集型进程。

进程层次结构:Unix进程家族树:init为根; Windows:地位相同。

进程与程序的区别:

  1. 进程更能准确刻画并发,而程序不能;
  2. 程序是静态的,进程是动态的;
  3. 进程有生命周期的,有诞生有消亡,是短暂的,程序是相对长久的;
  4. 一个程序可对应多个进程;
  5. 进程具有创建其他进程的功能。

进程映像:对进程执行活动全过程的静态描述,由进程地址空间内容硬件寄存器内容以及与该进程相关的内核数据结构内核栈组成:

  1. 与用户相关:进程地址空间(包括代码段、数据段、队和栈、共享库);
  2. 与寄存器相关:程序计数器、指令寄存器、程序状态寄存器、栈指针、通用寄存器等的值;
  3. 与内核相关:a.静态部分:PCB及各种资源数据结构;b.动态部分:内核栈(不同进程在进入内核以后使用不同的内核栈)。

上下文切换:将CPU硬件状态从一个进程切换到另一个进程的过程:

  1. 进程运行时,其硬件状态保存在CPU的寄存器(程序计数器、程序状态寄存器、栈指针、通用寄存器、其他控制寄存器)中;
  2. 进程不运行时,这些寄存器的值保存在进程控制块PCB中,当操作系统要运行一个新的进程时,将PCB的相关值送到对应的寄存器中。

3.5线程的引入

为什么在进程中再派生出线程:

  1. 应用的需要;
  2. 开销的考虑;
  3. 性能的考虑。

进程的两个基本属性:

  1. 资源的拥有者;
  2. CPU调度单位。有了线程之后,线程继承了CPU调度单位这一属性。

线程:进程中的一个运行实体,是CPU的调度单位,有时将线程称为轻量级进程。即在同一进程中增加了多个执行序列(线程),让这些执行序列可以并发执行,提高软件效率。

线程的属性:

  1. 唯一的标识符ID;
  2. 有状态及状态转换——需要提供一些操作;
  3. 不运行时需要保存的上下文,有上下文环境:程序计数器等寄存器;
  4. 有自己的栈和栈指针;
  5. 共享所在进程的地址空间和其他资源;
  6. 可以创建、撤销另一个线程,程序开始是以一个单线程进程方式运行。

3.6线程机制的实现

线程的实现有三种方式:

  • 用户级线程:
  1. 在用户空间建立线程库:提供一组管理线程的操作;
  2. 运行时系统:完成线程的管理工作(操作、线程表);
  3. 内核管理的还是进程,不知道线程的存在;
  4. 线程切换不需要内核态特权。

优点:a.线程切换快;b.调度算法是应用程序特定的;c.用户级线程可运行在任何操作系统上(只需要实现线程库);                 

缺点:a.内核只能将处理器分配给进程,同一进程中的两个线程不能同时运行于两个处理器上;b.大多数系统调用是阻塞的,因此,由于内核阻塞进程,故进程中所有线程也被阻塞。

  • 核心级线程:
  1. 内核管理所有线程管理,并向应用程序提供API接口;
  2. 内核维护进程和线程的上下文;
  3. 线程的切换需要内核支持;
  4. 以线程为基础进行调度。

例子:Windows

  • 混合——两者结合方法:
  1. 线程创建在用户空间完成;
  2. 线程调度等在核心态完成。

 例子:Solaris:多个用户级线程多路复用多个内核级线程。

3.7章节小结

  • 进程
  1. 并发性:任何进程都可以与其他进程一起向前推进;
  2. 动态性:进程是正在执行程序的实例——(1)进程是动态产生,动态消亡的(2)进程在其生命周期内,在三种基本状态之间转换;
  3. 独立性:进程是资源分配的一个独立单位,例如:各进程的地址空间相互独立;
  4. 交互性:指进程在执行过程中可能与其他进程产生直接或间接的关系;
  5. 异步性:每个进程都以其相对独立的、不可预知的速度向前推进;
  6. 进程映像:程序+数据+栈(用户栈、内核栈)+PCB。
  • 线程
  • 可再入程序(可重入):可被多个进程同时调用的程序,具有下列性质:(1)纯代码,即在执行过程中自身不改变;(2)调用它的进程应该提供数据区。
<think>我们正在讨论进程和线程管理相关问题的解决方案和最佳实践。根据之前的引用,我们可以从以下几个方面展开:1.线程进程的性能和效率优化(包括CPU密集型I/O密集型任务的处理)2.死锁的预防处理3.多线程中资源消耗异常问题的排查(如引用[4]中提到的chromedriver进程问题)4.现代并发模型(如虚拟线程)的应用我们将逐一讨论,并提供最佳实践。注意:在回答中,我们将引用之前的引用标记[^1]、[^2]等,以表明内容来源。现在开始详细解答。</think>### 进程和线程管理问题的解决方案最佳实践 #### 1. **线程/进程数量优化** [^2] - **CPU密集型任务**: $$线程数 ≈ 逻辑核心数 \quad \text{或} \quad 物理核心数 + 1$$ 示例:8核CPU → 8-9个线程 - **I/O密集型任务**: $$线程数 = (2 \sim 3) \times 逻辑核心数$$ 示例:8核CPU → 16-24个线程(利用I/O等待时间) - **混合型任务**: - 分离I/O和CPU操作到不同线程池 - 使用协程(如Go的goroutine)替代线程减少切换开销[^3] #### 2. **死锁预防处理** [^1][^5] ```mermaid graph TD A[死锁预防] --> B[按固定顺序获取锁] A --> C[设置锁超时机制] A --> D[使用无锁数据结构] E[死锁检测] --> F[维护锁关系图] E --> G[定期扫描资源分配图] E --> H[自动解除循环等待] ``` **最佳实践**: - 避免嵌套锁:单函数内最多持有一个锁 - 使用`tryLock()`替代阻塞锁(Java示例): ```java if (lock.tryLock(100, TimeUnit.MILLISECONDS)) { try { /* 临界区 */ } finally { lock.unlock(); } } ``` - 检测工具:Java的`jstack`,Python的`faulthandler` #### 3. **资源泄漏治理** [^4] **进程泄漏场景(如ChromeDriver)**: ```bash # Windows检测命令 tasklist | findstr "chrome" ``` **解决方案**: 1. 强制终止僵尸进程: ```bash pkill -f "chromedriver" # Linux taskkill /F /IM chromedriver.exe # Windows ``` 2. 代码级防护: ```python # Python with自动资源释放 with webdriver.Chrome() as driver: driver.get(url) ``` 3. 监控机制: - 定时检查进程树 - 设置内存阈值告警 #### 4. **现代并发模型实践** [^3] | 模型 | 适用场景 | 优势 | |---------------|-------------------------|-------------------------| | 虚拟线程(Java) | 高并发I/O任务 | 万级线程,低内存开销 | | 协程(Go/Python)| 异步I/O密集型 | 轻量级,无锁调度 | | Actor模型 | 分布式系统 | 消息隔离,自动容错 | **Java虚拟线程示例**: ```java try (var executor = Executors.newVirtualThreadPerTaskExecutor()) { IntStream.range(0, 10_000).forEach(i -> executor.submit(() -> { Thread.sleep(Duration.ofSeconds(1)); return i; }) ); } ``` #### 5. **性能调优工具链** - **诊断工具**: - Linux: `top`, `pidstat`, `perf` - Java: `jvisualvm`, `Arthas` - Python: `cProfile`, `py-spy` - **监控指标**: - CPU利用率 > 70% → 检查线程竞争 - 上下文切换 > 5万/秒 → 优化线程数 - 内存持续增长 → 检测资源泄漏 > **关键原则**: > 当线程等待时间占比 $W$ 计算时间 $C$ 满足 $\frac{W}{C} > 1$ 时, > 最优线程数 $N_{opt} = N_{core} \times (1 + \frac{W}{C})$
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值