并发编程基本概念(进程,线程,协程,线程池,同步/互斥)

2023-11-13

并发编程基本概念

一、进程的概念

计算机的核心是CPU,它承担了所有的计算任务;而操作系统是计算机的管理者,它负责任务的调度、资源的分配和管理,统领整个计算机硬件;应用程序则是具有某种功能的程序,程序是运行于操作系统之上的。

  1. 进程:从用户角度来说,是程序的运行/活动实体,即程序的一次动态执行过程,是一个动态的概念,而程序本身是一个静态的概念。从操作系统角度来说,进程是资源调度和分配的基本单位,也是能够独立运行的最小单位。有着动态性,独立性,并发性,结构性几个特征;
    注:虽然线程在执行上有着独立性,不依赖于其它线程,但是还是依赖于进程的系统资源,因此,个人认为,进程才是真正意义上的独立。

  2. 进程的组成:进程一般由程序、数据集合和进程控制块三部分组成。

  • 程序:是进程执行的指令集(代码段),用于描述进程要完成的功能;
  • 数据集合:是程序在执行时所需要的数据(数据段)和工作区(如用户/系统堆栈)
  • 进程控制块(Process Control Block,简称PCB):是系统中一个存放进程的描述和控制信息的数据结构,是进程存在的唯一标识。操作系统使用PCB来控制和管理进程,其包含了标识信息(进程ID(PID)等),上下文信息(寄存器内容,堆栈指针),控制信息(调度信息,通信信息,资源占用信息)等多种描述/控制信息;
  • 线程部分:如果是在多线程系统,那么每个进程还包含至少一个线程,用户/系统堆栈在线程中,每个线程都有相应的堆栈;
  1. 进程的五个状态:
  • 创建状态:进程正在创建,还不能运行。操作系统在创建进程时要进行的工作包括分配和建立进程控制块表项、建立资源表格并分配资源、加载程序并建立地址空间;
  • 就绪状态:进程已经获得除了CPU之外的所有必要资源,正等待CPU,即为就绪态;创建完之后等待或者是等待下一次时间片;
  • 执行状态:进程获得了CPU占有权限,正在执行,为执行态;
  • 阻塞状态:正在执行的进程由于某种事件而暂时无法继续执行,从而被阻塞,例如中断,异常,系统调用等等,为阻塞态;
  • 终止状态:进程已经结束,等待操作系统进行善后处理,例如释放分配的资源,对PCB进行清零等等,为终止态;

二、线程的概念

早期的操作系统本来没有线程的概念,但随着计算机的发展,对CPU的要求越来越高,进程之间的切换开销较大,已经无法满足越来越复杂的程序的要求了。于是就发明了线程。

  1. 线程:是操作系统独立调度和分派的基本单位,也是能够进行运算调度的最小单位,是进程中一个单一顺序的控制流,为进程的实际运作单位多条线程共享所属进程中的全部系统资源,如虚拟地址空间,打开的文件和信号量等,但每个线程有各自的调用栈,寄存器环境,线程本地存储等。
  2. 线程组成:
  • 线程控制块: 线程ID、当前指令指针(PC),线程状态,线程阻塞时保存的线程资源等;
  • 寄存器环境: 用来存储运行时线程的一些局部变量,但不能存储其他线程的相关变量;
  • 调用栈: 系统堆栈/用户堆栈;

Tips: 内核创建进程,创建进程的同时创建进程控制块,创建进程自己的堆栈(用户栈和内核栈)
用户栈:进程在用户空间时创建的栈,比如一般函数调用;
系统栈:操作系统空间的一块固定区域,可以用于保存中断现场、保存操作系统子程序间相互调用的参数、返回值等;

三、进程和线程的比较

  1. 定义:线程是独立调度和分派的基本单位,是进程中单一顺序的控制流,而进程是操作系统进行资源分配和调度的最小单位,也是独立运行的最小单位;
  2. 代码:进程包含线程代码,由至少一个线程组成,线程代码仅仅是进程代码的一部分;
  3. 资源:进程可以独立申请资源并相互独立,是资源分配的基本单位;但同一进程下的各线程的资源依赖于进程,共享进程的内存空间(包括代码段、数据集、堆等)及一些进程级的资源(如打开文件和信号),不同进程的线程相互不可见;
  4. 调度和切换:同一进程的线程切换不会引起进程切换,反之进程切换一定会引起线程切换。另外,线程上下文切换比进程上下文切换开销小得多,速度快得多;
  5. 生命期:进程撤销会导致它的所有线程被撤销,而线程撤销不会过于影响进程。

问题:进程上下文切换的流程是怎样的?线程切换又是怎样?

  1. 上下文切换: 从当前执行任务切换到另一个任务执行的过程,但为了确保下次能从正确的位置继续执行,在切换之前,会保存上一个任务的状态。
  2. 进程切换:
  1. 保存当前进程的处理器上下文至PCB(寄存器,堆栈指针等);更新PCB信息,如修改进程状态;将进程的PCB移入相应的队列;
  2. 选择新进程,更新PCB信息;根据选中进程设置CPU用到的页表和存储保护信息;根据被选中进程恢复处理器现场。
    注:由于涉及到当前进程CPU现场保护,**CPU的页表项缓存替换(切页表)**以及CPU现场恢复,因而代价大。
    注:由于不同的进程维持的页表也不同,那么当进程切换后,CPU缓存中的页表项就都失效了,因此要切换cache中的页表项,而不是说对进程的页表进行重定位。–这是个人理解,可能有误,敬请指正。网上有的还要说换出数据段和代码段啥的,很迷,这不就意味着将原本进程的资源都释放啦?就切换一个进程,个人认为不至于。
  1. 线程切换:
  1. 保存当前线程的处理器上下文至TCB(寄存器,堆栈指针等);更新TCB信息,如修改线程状态;将线程的TCB移入相应的队列;
  2. 选择新线程,更新TCB信息;根据被选中线程的TCB恢复处理器现场。
    注:这里和进程切换相比少了一个切页表的过程,只需要关注处理器上下文信息就可以了,因此快得多。

问题:多线程为什么比多进程好?(个人观点)
答:设定一个场景,当前任务有很多个子任务,每个子任务可以既通过子进程的方式来处理,也可以通过线程的方式来处理,那么这种情况下,使用多线程的开销要小,因为线程创建,切换和撤消的开销远小于进程。因此,应该是任务能用多线程处理的情况下,多线程性能比多进程好,但以前的系统不支持多线程,那么性能肯定有所降低。

四、协程

  1. 定义:协程,拥有自己的寄存器上下文和用户栈,完全由用户程序自身控制,内核不可见,因此,没有类似PCB,TCB的控制块,是一种比线程更加轻量级的存在。

  2. 特征:

  • 拥有自己的寄存器上下文和用户栈;
  • 所有协程共享全局变量;
  • 协程之间需要相互协调执行,单次只能运行一个协程,无法并行执行;
  1. 为什么要引入协程?(个人观点)
  • 在I/O密集的多线程系统中,往往需要CPU去等IO操作,从而进行线程切换,当I/O操作完成之后,再通知系统将线程切换回来,每次的线程切换都需要从用户态切换到内核态来进行操作,带来了大量性能的消耗;
  • 那么我们能不能让用户程序自己来管理这样的切换呢?这就出现了协程。当前协程需要I/O操作时,让出CPU的控制权,唤醒其它协程来使用CPU,当I/O处理完成时,其它协程接收到了I/O返回的信息时,再唤醒当前协程,将控制权让回来,协程之间通过这种方式完成协作,避免了大量的用户态到内核态的陷入操作。

五、线程池

  1. 定义:一系列线程的集合称为线程池,里面的线程能够重复使用,在任务处理完毕之后线程不会撤销,而是阻塞等待下一个任务;
  2. 执行机制:

线程池在系统启动时即创建大量空闲的线程,程序将任务传给线程池,线程池就会唤醒空闲线程来执行,执行结束以后,线程并不会撤销,而是成为空闲状态,即被阻塞等待执行下一个任务。另外,可以同时向线程池提交多个任务。

  1. 引入线程池的原因:

多线程运行时,系统不断的启动和关闭新线程,成本非常高,会过渡消耗系统资源,以及过渡切换线程的危险,从而可能导致系统资源的崩溃,这时,可以使用线程池来处理任务,实现线程的复用以及创建/撤销代价的分摊。

  1. 一些实现方法(个人观点):
  • 使用一个任务队列来存储任务列表;
  • 维持两个线程列表,一个为空闲列表,一个为阻塞列表;
  • 使用两个参数变量来控制线程数量,长时间没有任务时维持最小数量,任务繁忙时,维持最大数量;
  • 使用信号量,条件变量等等机制来保证线程安全;

六、常见的线程/进程同步/互斥策略

同步:协调进程/线程的执行次序,使得并发进程/线程间能够有效地共享资源和相互合作,保证数据一致性;
互斥:进程/线程排他性的运行某一段代码,任何时候只有一个进程/线程能够运行,使得其独占资源。

  1. 信号量(semaphore):一般为整数,提供PV两个原子操作(P等待信号量,V释放信号量)。
  • 互斥:保证某个资源仅仅被有限个进程/线程同时访问,在访问资源之前,进程/线程必须获取一个信号量(P操作,值-1),当获取不到,例如值为0的时候,则阻塞;执行完代码段后,必须释放信号量(V操作,值+1),信号量的初始值即为最大的可同时访问资源的进程/线程数量。
  • 同步:先执行的进程/线程释放信号量(V操作),后执行的进程/线程获取信号量才能执行(P操作),从而保证程序执行的先后顺序。
  1. 临界区:各进程/线程涉及到临界资源的代码段;临界资源指一次仅仅允许一个进程/线程使用的资源;临界区一般需要和互斥锁一起使用才能够保证资源的互斥性。
  2. 互斥锁(mutex): 进程/线程在进入临界区之前,必须获取与临界区相关联的互斥锁;如果已有另一进程/线程拥有了临界区的互斥锁,其他进程/线程就不能再进入其中;这些进程/线程必须阻塞等待,直到当前的属主进程/线程释放该互斥锁;互斥锁实质上是二值信号量。
  3. 自旋锁: 和互斥锁类似,都能够保证资源的互斥访问。不同的在于,对于互斥锁,如果资源已经被占用,资源申请者只能进入睡眠状态。但是自旋锁不会引起调用者睡眠,如果自旋锁已经被别的执行单元保持,调用者就一直循环在那里看是否该自旋锁的保持者已经释放了锁,"自旋"一词就是因此而得名。适用于锁保持时间较短的场景,由于不需要阻塞,效率较高,但是容易发生死锁和过多占用CPU资源。
  4. 读写锁:适用于读者/写者相类似的问题,读者可以共享,写者只能够独占,另外,如果读者,写者同时访问,写者优先级高于读者。
  • 读写锁是写模式加锁时,解锁前,所有对该锁加锁的线程都会阻塞。
  • 读写锁是读模式加锁时,如果线程以读模式加锁会成功,如果线程以写模式加锁会阻塞
  • 读写锁是读模式加锁时,既有试图以写模式加锁的线程,也有试图以读模式加锁的线程,那么读模式会读阻塞随后的读模式锁请求,优先满足写模式锁,读锁、写锁并行阻塞,写锁优先级高。
  1. 条件变量:每个条件变量维持了一个阻塞队列,当某种当前进程/线程不满足对应条件时,执行wait()操作,阻塞相关进程/线程,直到另外一个进程/线程在该条件变量上执行signal()操作,将其唤醒,并移出队列。有点类似于信号量,个人认为信号量的值就相当于条件变量的条件,而我们一般不关注条件变量的值,而是关注其相应的条件,其条件可以更加任意,不一定是一个整数值。
  2. 管程:定义了一个数据结构(局部共享变量和条件变量)和能为并发进程所执行的(在该数据结构上)的一组操作,这组操作可以同步进程以及修改管程内部数据结构,维持以下两个队列。
  • 管程入口队列:当进程试图进入一个已经被占用的管程时,进入入口队列等待,需要使用互斥锁;
  • 资源等待队列:管程内进程因资源占用等原因不能够继续运行时,临时放弃管程使用权限,进入等待队列,直到另外一个进入管程的进程将其唤醒;

信号量机制和管程机制的区别(个人观点):

  • 信号量机制:访问共享资源的每个进程都需要自己实现对于共享资源的访问逻辑,同步/互斥等等,当每个进程的PV操作太多时,容易混乱,发生死锁,难以维护;
  • 管程机制:定义一个抽象数据类型,统一地定义共享资源的访问逻辑,外部代码代码不需要考虑太多逻辑,只需要调用管程的接口函数以及注意管程的互斥操作即可。另外,管程中的线程也可以通过条件变量的机制,临时放弃管程的互斥访问,让其他线程进入到管程中来。这是一个不同于临界区代码的地方。

注:以上资料为本人在学习过程中整合理解,很多都是个人理解观点,如有错误敬请指正。

参考文献:

  1. 一文读懂什么是进程,线程,协程
  2. 用户堆栈和系统堆栈的区别
  3. 百度百科:线程
  4. 百度百科:进程
  5. 【C/C++】 Pthread线程池
  6. 一文让你明白CPU上下文切换
  7. 一篇文章搞懂线程池
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

并发编程基本概念(进程,线程,协程,线程池,同步/互斥) 的相关文章

  • Qtcreator中来调用python的函数的用法

    以下内容是参考博客 https blog csdn net alxe made article details 83382159 由以上大神的博客作为参考成功实现的 一 先说几点注意的地方 1 就是需要将python的路径在pro中加载进来

随机推荐

  • 和利时系统如何下装服务器,和利时服务器如何将A设置B

    和利时服务器如何将A设置B 内容精选 换一换 系统盘镜像和数据盘镜像为128个 整机镜像为10个 没有限制 可以 支持中国站和国际站的帐号之间共享镜像 但是仅限于中国站和国际站共同拥有的区域 例如 您在中国站的 华北 北京四 的镜像不能共享
  • ShardingSphere报错-java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer

    目录 一 场景 二 报错信息 三 排查 四 原因 五 解决 一 场景 1 项目使用ShardingJDBC操作数据库 2 查询SQL执行报错 但将sql复制到navicat中执行 是正常的 二 报错信息 nested exception i
  • 2021-06-15

    com aspose diagram afr Unexcepted eof 有没有大佬遇到过这个问题 救命
  • 华为OD机试 Java 几何平均值最大子数组

    题目 代码 import java util public class MaxGeometricMean public static void main String ar
  • Vue 响应式实现原理

    准备工作 数据驱动 响应式的核心原理 发布订阅模式和观察者模式 数据驱动 数据响应式 双向绑定 数据驱动 数据响应式 数据模型仅仅是普通的 JS 对象 而当我们修改数据时 试图回进行更新 避免了繁琐的 DOM 操作 提高开发效率 双向绑定
  • 类是公共的 应该在 java中声明_Java入门-类HelloWorld是公共的,应在名为HelloWorld.java的文件中声明...

    开始学习java了 搭好环境 notepad 中新建一个java文件 新建一个HelloWorld类 public class HelloWorld public static void main String args System ou
  • Verilog自动生成 CRC 校验代码

    CRC 循环冗余码 表示形式 多项式G x G x X4 X3 1 假设 输入数据 Data 选定的多项式G x 是x4 x3 1 所以G M 11001 CRC Data mod G 注 CRC的位数要始终比G少1位 因为余数肯定比除数小
  • JAVA中使用FTPClient上传下载

    JAVA中使用FTPClient上传下载 在JAVA程序中 经常需要和FTP打交道 比如向FTP服务器上传文件 下载文件 本文简单介绍如何利用jakarta commons中的FTPClient 在commons net包中 实现上传下载文
  • 2023华为OD机试真题Java实现【深度优先搜索/机器人】

    题目描述 现有一个机器人 可放置于M N的网格中任意位置 每个网格包含一个非负整数编号 当相邻网格的数字编号差值的绝对值小于等于1时 机器人可以在网格间移动 问题 求机器人可活动的最大范围对应的网格点数目 说明 网格左上角坐标为 0 0 右
  • 全网最全的私网多种穿透互联技术解析

    多种业务场景存在私网的情况下需要对网络的互联互通 视情况使用以下多种网络工具进行互联 以下使用的工具都是跨平台的 适用大多数操作系统 Openvpn 前言 操作系统 Centos6 Centos7 Centos8 openvpn的虚拟网卡是
  • 动态规划——购物单

    HJ16 购物单 这是一道典型的0 1背包问题 一开始的反应就是外层循环正向遍历物品 内层循环反向遍历背包容量 但由于物品增加了附件这一属性 使得这道题难度增加了不少 可以参考该视频处理物品的思路 每个物品用长度为6的数组来分别保存索引为i
  • CNN

    卷积神经网络 Convolutional Neural Networks 是一种深度学习模型或类似于人工神经网络的多层感知器 常用来分析视觉图像 CNN在图像分类数据集上有非常突出的表现 DNN与CNN 下图为DNN 下图为CNN 虽然两张
  • 低压差线性稳压电源(LDO)原理、参数及应用

    文章目录 前言 一 低压差线性稳压电源是什么 二 LDO工作原理 1 NPN稳压器 2 LDO稳压器 3 准LDO稳压器 4 场效应管 FET 作为导通管LDO 三 LDO的参数 1 裕量电压 2 静态电流和接地电流 3 效率 4 PSRR
  • 错误:‘uuid_t’在此作用域中尚未声明

    安装TFS报错 1 2 3 4 5 6 7 8 9
  • MYSQL 中 LIMIT 用法

    mapper文件中的sql 在实体类中定义的属性 start 从第几条记录开始 size 读取几条记录 select id findAllUsers parameterType Map resultType entity IUser gt
  • 华为OD机试 - 座位调整(JS)

    题目描述 疫情期间课堂的座位进行了特殊的调整 不能出现两个同学紧挨着 必须隔至少一个空位 给你一个整数数组 desk 表示当前座位的占座情况 由若干 0 和 1 组成 其中 0 表示没有占位 1 表示占位 在不改变原有座位秩序情况下 还能安
  • java--注解和反射

    一 注解 1 1 注解Annotation的概念 1 注解的作用 注解Annotation是从JDK1 5开始引入的新技术 我们在编程中经常会使用到注解 它的作用有 1 编译检查 比如 SuppressWarnings Deprecated
  • 【使用html2pdf将页面生成PDF文件】

    前端使用html2pdf将页面生成PDF文件 一 下载js文件 链接 https cdnjs cloudflare com ajax libs html2pdf js 0 10 1 html2pdf bundle min js 二 引入js
  • poi 操作 PPT,针对 PPTX--图表篇

    poi 操作 PPT 针对 PPTX 图表篇 文章目录 poi 操作 PPT 针对 PPTX 图表篇 1 读取 PPT 模板 2 替换标题 4 替换图表数据 接下来对 ppt 内的图表进行操作 替换图表的数据 原幻灯片样式 1 读取 PPT
  • 并发编程基本概念(进程,线程,协程,线程池,同步/互斥)

    并发编程基本概念 一 进程的概念 计算机的核心是CPU 它承担了所有的计算任务 而操作系统是计算机的管理者 它负责任务的调度 资源的分配和管理 统领整个计算机硬件 应用程序则是具有某种功能的程序 程序是运行于操作系统之上的 进程 从用户角度