进程和线程

目录

进程

什么是进程?

进程在系统中是如何管理的?

PCB(进程控制块)

PID

内存指针

文件描述符表

状态

优先级

记账信息

上下文

进程调度

进程间通信

线程

为什么需要使用线程?

什么是线程?

线程与进程的关系


进程

什么是进程?

进程(Process)是操作系统提供的一种 "软件资源",是 操作系统 对一个 正在运行的程序 的一种抽象,即,可以把 进程看做程序的一次运行过程,进程依赖于程序运行而存在,进程是动态的,程序是静态的

当我们打开任务管理器,就可以看到:

每个进程在执行过程中,都需要消耗一定的硬件资源,因此,计算机中的每个进程在运行的时候,都需要为其分配一定的资源空间, 也就是说,在操作系统内部,进程是系统分配资源的基本单位

进程在系统中是如何管理的?

要想管理系统中的进程,首先需要对进程进行描述,每个进程在操作系统中都有一个对应的 进程控制块(PCB),PCB 是操作系统维护的数据结构,用于存储进程的状态信息和控制信息 

然后再将系统中的进程组织起来,操作系统使用数据结构(如 线性表、搜索数等)将 PCB 组织起来,方便管理时进行增删查改

PCB(进程控制块)

PCB(Process Control Block)是实现进程管理的核心数据结构,PCB中包含了上百个属性(进程的标识符、状态(如运行、就绪、等待)、程序计数器(指向下一条将执行的指令)、内存指针(指向进程的地址空间)、上下文信息(包括寄存器的状态)、进程优先级、所属用户等信息...),接下来我们就来了解一些常见的属性

PID

PID(Process Identifier)进程标识符,是进程的身份标识,用来标识操作系统中的每一个进程。每一个进程都有一个唯一的 PID,操作系统通过 PID 来识别和管理不同的进程

内存指针

内存指针,用于描述进程使用内存资源的详细情况,在进程运行过程中,需要消耗一定的系统资源,其中,内存就是一种重要的资源,在进程运行前,需要向操作系统申请一块内存空间,而内存指针,就是用来描述当前进程都能使用哪些内存、哪些部分存放的是指令(代码),哪些部分存放的是数据

文件描述符表

在进程运行过程中,通常需要访问硬盘,操作系统将硬盘这样的硬件设备封装成了文件,因此,我们只需要统一使用 文件 的方式来进行操作

每个进程都有一个固定大小的文件描述符表,通常是一个数组或者类似数据结构。每个表项存储了与打开文件相关的信息,如文件指针、文件状态标志(如读、写、追加等)、文件打开模式(只读、只写、读写等)

状态

进程在操作系统中可以处于不同的状态,这些状态反映了进程在其生命周期中的不同情况和条件,如就绪状态、阻塞状态

优先级

优先级描述的是:在多个进程等待系统调度的过程中,多个进程之间调度的先后关系

记账信息

针对每个进程占用了多少 CPU 时间进行统计,然后根据统计结果来进一步调整调度的策略

上下文

上下文是支撑进程调度的重要属性,相当于 存档 和 读档

每个进程在运行过程中,会有很多的中间结果,存储在 CPU 的寄存器中,当操作系统在多个任务之间切换时,会保存和恢复每个任务的状态,这一过程称为上下文切换。上下文切换涉保存上下文恢复上下文

多个任务的切换,就涉及到 进程调度

进程调度

调度 是指操作系统根据一定的调度算法,决定将CPU分配给哪个进程执行的过程

CPU(中央处理器)是计算机的核心组件,负责执行程序指令和处理数据,承担了所有的计算任务,但 单个 CPU 一次只能执行一个任务,也就是运行一个进程,其他进程处于非运行状态,若出现操作系统需要同时执行多个任务的情况,这时候应该怎么办呢?

这就涉及到了 分时复用,并发执行

CPU 核心只有一个,因此,可以先执行 进程1 的代码,执行一会后,让 进程2 执行,进程2 执行一段时间后,再让 进程3 执行...

只要切换速度足够快,人是感知不到这个切换过程的,因此,在我们看来,多个进程就是 "同时执行" 的

CPU 的频率一般都是以 GHZ 为单位,也就是说,CPU 一秒钟能够执行几十亿条指令,这也就意味着:在短时间内,CPU 可以进行很多次任务的切换,只要切换速度足够快,人就感知不到,但是,若系统进程太多时,CPU 负担太重,就会出现 卡顿 的情况

现代的 CPU 通常都是 多核 的,也就意味着可以同时执行多个进程(如,一个 4 核 CPU,就可以同时运行 4 个进程),此时,不同核心上的CPU 就是同时执行的,而不是靠快速切换模拟的 同时执行,也就是 并行执行

但由于 同一时间 运行的任务可能超过 CPU 的核心数,因此,并发执行仍然存在,每个核心仍然需要分时复用

多个进程是并行执行还是并发执行,都需要看系统的调度,而系统如何进行调度,取决于系统模拟器模块是如何实现的,我们一般都感知不到,因此,往往把 并行 和 并发,通称为 并发

了解了 进程调度 之后,我们就能进一步理解 上下文,当 进程1 执行一段时间后,此时需要执行 进程2 了,就需要在 进程1 调度出 CPU 之前,将当前寄存器中的数据存储起来,也就是 保存上下文;而当下一次调度 进程1 时,需要继续执行 进程1 的代码,就需要将 上次存储的数据 加载到 CPU 的对应寄存器中,也就是 恢复上下文

进程间通信

进程是操作系统进行资源分配的最小单位,这就意味着各个进程相互之间是无法感受到对方的存在的,因此,进程之间相互具有 "隔离性"

虽然进程具有独立性,但在有些场景,多个进程可能需要相互通信和协作,例如数据共享、消息传递等。操作系统提供了多种进程间通信(IPC)的机制,如管道、信号量、消息队列、共享内存等。进程间通信的实现可以通过操作系统提供的系统调用或特定的API来完成,确保进程之间可以安全地交换信息和协作执行任务。

在了解了 进程 之后,我们来学习 线程 相关知识

 

线程

为什么需要使用线程?

多任务操作系统,当然希望系统能够同时运行多个程序(若是 单任务的系统,也就不涉及进程,不需要管理,更不需要调度),因此,从本质上来说,进程解决的是 "并发编程" 的问题

进程可以很好的解决 并发编程 这样的问题,但某些特定的情况,例如,需要频繁创建和销毁进程时,此时使用 多进程编程,系统开销就会很大(开销主要体现在 资源申请 和 资源释放 上)

为了解决上述问题,就引入了 多线程

什么是线程?

线程,也可以称为 轻量级进程,在进程的基础上做出了改进,保持了 独立调度执行 这样的 并发支持,同时省去了 分配资源、释放资源 带来的额外开销

多线程是如何做到的呢?

在前面我们学习了使用 PCB 来描述一个进程,一个进程有一个PCB,我们来看不同进程分配的内存空间:

线程在系统中的调度规则,和 进程 是一样的,线程的 PCB 中也有 状态、优先级、上下文、记账信息...,我们来看不同线程分配的内存空间:

PCB 中有一个重要的属性——内存指针(描述进程使用内存资源的详细情况),多个线程的PCB 中的内存指针,指向的是同一个内存空间,这也就意味着,只需要在创建第一个线程的时候从系统分配资源,后续的线程,就不必分配,直接共用前面的那份资源,除了内存之外,文件描述符表 也是多个线程共用一份的

任意两个线程都能够实现资源共享吗?

当然不是,我们将能够资源共享的这些线程划分为一组,称为 线程组:

我们可以看到,每个进程,都包含了一个或多个线程,在没有引入线程时,进程是资源分配的基本单位,也是调度执行的基本单位;而有了线程之后,进程是资源分配的基本单位,线程是调度执行的基本单位

我们通过一个例子来进一步理解 线程 和 进程:

假设此时有一个任务需要完成——生产100个玩偶

此时有一个工厂(进程),其中有一个工人(线程)来完成这个任务

此时应该如何提升生产效率呢?

若以多进程的方案,我们可以再找一个新的工厂(创建一个新的进程),来共同完成任务,此时能够提升效率,但成本很高(创建一个新的进程需要申请更多的资源)

而以多线程的方案,仍是原来的工厂,但我们再找一个工人(创建一个线程)来完成这个任务,此时也能够提升效率,且这种方案成本更低(资源开销更小)

若我们让更多的工人来完成这个任务(这些工人共享同一份资源,共同使用工厂的工具进行生产),此时效率就会更高,与之对应的,若我们找更多的工厂,成本就会更高

但是,引入的工人越多越好吗?

当引入工人达到一定数量的时候,再尝试引入新的工人,就没办法提升效率了,因为工厂的生产工具没有那么多,也就是说,当线程数量太多时,线程之间就会相互竞争 CPU 的资源,此时非但不会提高效率,反而还会增加调度的开销

采用多线程能够减少资源开销,但共享资源也有其副作用

若工人A 在拿工具时没拿到,生气了,直接将工厂电闸一拉,此时整个工厂都不能再继续生产了

也就是说,若一个线程抛出了异常,并且没有处理好,就可能导致整个进程被终止

在学习了 进程 和 线程 之后,我们来总结一下 进程 和 线程 之间的关系

线程与进程的关系

1. 进程是包含线程的,每个进程至少有一个线程存在,即主线程

2. 每个线程都是一个独立的执行流,都可以执行代码,且单独参与到 CPU 调度中

3. 每个进程都有自己的资源,进程和进程之间不共享资源,同一个进程的线程之间共享一份资源(内存空间和文件描述符表)

4. 进程是资源分配的基本单位,线程是调度执行的基本单位

5. 进程和进程之间互不影响,同一个进程中的某个线程抛出异常,可能会影响到其他线程

6. 同一个进程中的线程之间可能会互相干扰,引起线程安全问题

7. 线程也不是越多越好,若线程太多,调度开销可能会非常大

  • 73
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 52
    评论
Linux中的进程线程有以下几个区别: 1. 数据结构:在Linux中,线程是通过进程模拟出来的,没有真正意义上的线程数据结构。而在Windows中,操作系统为线程创建了thread_struct数据结构,因此有真正意义上的线程。 2. 执行流:在Linux中,每个线程实体对应着操作系统下的一条执行流,通过PCB(task_struct)来模拟。而用户态下创建的线程是通过线程库(pthread_struct)来进行管理。 3. 标识作用:在Linux中,轻量级进程ID(tid)对不同的线程起标识作用,操作系统在进行调度时使用tid。而进程ID(pid)对不同的进程起标识作用。在只有一个线程进程中,tid的值等于pid的值。 4. 线程私有部分:线程私有部分包括运行时栈、一组寄存器/硬件上下文/任务状态段等。 5. 多线程提高效率:多线程能够提高效率的原因是多核和单核环境下的不同。在多核环境下,多线程可以将庞大的任务分成若干份,并交给不同的线程进行处理,同时执行不同步骤的代码,从而提高效率。而在单核环境下,多线程并发执行,使用线程切换来提高整体代码的运行效率。 6. 进程线程的区别:进程是程序运行的实例,是系统分配资源的基本单位,拥有独立的地址空间;线程进程中的一条执行流,是CPU调度的基本单位,共享同一地址空间。创建和撤销进程的开销大于线程,不同进程间不会互相影响,而一个线程挂掉可以将整个进程挂掉。
评论 52
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

楠枬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值