当前位置: 首页 > news >正文

【iOS】多线程基础

【iOS】多线程基础

文章目录

  • 【iOS】多线程基础
    • 前言
    • 进程与线程
      • 进程
        • 进程的状态
        • 进程的一个控制结构
        • 进程的上下文切换
      • 线程
        • 为什么要用线程
        • 什么是线程
        • 线程和进程的关系
        • 线程的上下文切换
      • 线程和进程的优缺点
    • 小结

前言

笔者由于对于GCD不是很了解,导致了项目中网络请求哪部分的一个代码冗长且逻辑混乱,很多时候出现了问题也不知道怎么解决,所以笔者决定学习一下多线程的内容,方便自己之后对于GCD的一些内容的理解。

进程与线程

对于任何一个学习计算机的人而言,对于进程和线程这两个词语一定不陌生,但是要具体说出二者的区别,可能还是会支支吾吾说不出个所以然,这里笔者简单介绍一下有关进程和线程的内容。

进程

我们编写的代码都只是一个存储在计算机硬盘的一个静态文件,通过编译后会变成一个二进制可执行文件,当我们运行这个可执行文件后,他会进入内存中,然后我们计算机的cpu会开始执行这个程序的每一条指令,这时候这个运行中的程序就被称作进程, 也就是这个运行的程序实例被叫做进程。

用官方一点的话来讲就是:进程(Process)是计算机中具有一定独立功能的程序关于某个数据集合的一次运行活动。 它可以申请和拥有系统资源,是系统进行资源分配和调度的基本单位(有了多道程序的概念,操作系统就可以对每个程序进行资源的分配)。

这时候,我们的计算机如果执行一个读取硬盘文件的数据内容被执行了,当运行执行读取文件的指令的时候,cpu开始从硬盘读取数据,这里我们不难发现一个问题,我们计算机读取硬盘的顺序是非常缓慢的,如果我们一直让计算机等待这个文件执行完然后在执行下面的内容的话,我们会浪费很多时间,cpu的利用率是非常的低下的。

举个例子,就好比我们吃饭的时候我们一直等待厨师把饭做好,在这期间我们什么事情也不做,就单纯的等待吃饭,这时候我们一般会去抽时间做不同的事情,然后等厨师做好饭就回来吃。所以现在的计算机也采用了这种思想,如果在执行一个进程中读取文件的内容的时候,cpu会切换到另一个进程中去执行另一个进程的相关内容,当硬盘的数据返回的时候,cpu会收到一个中断,cpu在回来执行这个进程的内容。

image-20241130155344174

这种 多个程序,交替执行的思想,就是cpu管理多个进程的初步想法。虽然一个单核的cpu在某一刻只能执行一个进程,但是在一个时间段内却可以执行多个进程,这样就会给我们产生一种并行的错觉,好像这几个进程是一起执行的,但是实际上这种方式叫做并发

image-20241130155734013

现在的主流操作系统都是支持”多任务“的操作系统。

举个例子:也就是操作系统可以同时运行多个任务。比如,你可以一边用浏览器上网,一边听音乐,一边写代码,对于操作系统而言,这就是多任务。

这种并发的效果是通过什么实现的呢?这里笔者引用一段博客:

答案就是时间片轮转调度:简单地说就是把一个处理器划分为若干个短的时间片,每个进程会被操作系统分配一个时间片(即每次被 CPU 选中来执行当前进程所用的时间),每个时间片依次轮流地执行处理各个应用程序,时间一到,无论进程是否运行结束,操作系统都会强制将 CPU 这个资源转到另一个进程去执行,由于一个时间片很短,相对于一个应用程序来说,就好像是处理器在为自己单独服务一样,从而达到多个应用程序在同时进行的效果。通俗的说就是讲时间分为一个个极短的时间段,在相应的时间短中执行相应的程序,因为时间段的时间极短,在我们和程序看来就好像是CPU同时处理多个进程一样。
【iOS】—— 多线程编程八重曲之(一)- 多线程基础

image-20241130161029555

正如同上图每一个方块都是一个时间片,我们的计算机会给这三个程序分配对应的时间片,先运行一个程序,在这个时间片用完之后迅速切换到另一个进程中,再次执行对应的一个时间片,就这样循环往复从而实现了一个并发的效果(原因是时间片非常的短暂,人察觉不出来他的区别)。

进程的状态

在上面的多进程的例子中,我们发现进程大致有着 运行—暂停—运行的一个活动规律,就一般情况来说,一个进程不是自始自终连续不停的运行的,他与并发执行中的其他进程的执行是互相制约的。

所以一个进程在活动期间主要具备了三个基本状态: 运行状态就绪状态阻塞状态

image-20241130161959611

  • 运行:进程占用cpu
  • 就绪:可运行,但是因为某些原因停止运行
  • 阻塞:该进程正在等待某一事件的发生而停止运行

自然还会有另外两个状态,创建和结束的状态

image-20241130162250966

这里笔者直接引用一段别的大佬对于这个状态变迁的描述

image-20241130162649146

图片来自:进程管理

其实进程还有被挂起的一个状态,笔者这里还不是很能理解相关内容,这里涉及到了一个虚拟内存的内容,笔者会在之后了解相关内容。

进程的一个控制结构

在操作系统中是采用 **程序控制块(PCB)**这个数据结构来描述进程的。PCB是一个进程存在的唯一标识,这里笔者可以结合mac的一个活动监视器来解释相关内容。

image-20241130163913407

他包含以下内容:

进程描述内容

  • 进程标识符,也就是上图中的PID
  • 用户标识符,就是上图中用户对应的内容。

进程控制和管理信息

  • 进程的一个状态,如new,ready
  • 进程优先级,进程抢占cpu的优先级

资源分配清单

  • 有关内存地址空间的信息

cpu相关信息

  • CPU各种寄存器的值,以便进程被重新执行后,都能从断点处继续执行。

通过PCB我们就可以实现一个多进程的一个并发。而PCB与PCB之间是用链表来组织的,将就绪状态的进程链接在一起,就是就绪队列。将等待状态的进程链接在一起叫做阻塞队列。

进程的上下文切换

前面我们提到进程间的切换,这个从一个进程切换到另一个进程中运行,被称为上下文切换。

我们也提到了现在的操作系统都是多任务的,所以在每个任务运行钱需要知道任务从哪里进行一个加载,从哪里开始运行。

这个时候,我们就啊哟先帮cpu设置好寄存器和程序计数器。

前者是一块运行速度极快的内存,后者是一个cpu将要执行指令的位置,或者即将执行的下一条指令的位置。这两个部分是CPU执行任何任务前,必须依赖的环境,这个环境就叫做CPU上下文

所以CPU上下文切换接可以理解为:

CPU 上下文切换就是先把前一个任务的CPU上下文(CPU 寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。

cpu的上下文切换分成:进程上下文, 线程上下文, 中断上下文

进程的上下文主要包含了:虚拟内存, 栈, 全句变量等用户需要的资源,还包含了寄存器和内核堆栈的等内核空间的资源。

image-20241130171218628

线程

为什么要用线程

这里笔者直接引用一段话:

在早期的操作系统中并没有线程的概念,进程是拥有资源和独立运行的最小单位。任务调度采用的是时间片轮转抢占式调度方式,而进程作为任务调度的最小单位,每个进程有各自独立的一块内存,使得各个进程之间内存地址相互隔离。

后来,随着计算机技术的发展,可运行的进程越来越多。进程出现了很多弊端,一是由于进程是资源拥有者,创建、撤消与切换存在较大的时空开销,因此需要引入轻型进程;二是由于对称多处理机(SMP)的出现,可以满足多个运行单位,而多个进程并行开销过大。因此出现了能独立运行的基本单位 —— 线程(Threads)。【iOS】—— 多线程编程八重曲之(一)- 多线程基础

其实线程的出现,主要还是为了减少上下文切换的时候浪费的系统开销,线程之间可以并发运行且共享相同的地址空间,从而减小了进程上下文切换的开销,让程序运行更加流畅。

什么是线程

线程是程序执行中一个单一顺序控制流程,是程序执行流的最小单元,是处理器调度和分派的基本单位。

同一进程中内多个线程可以共享代码段,数据段,打开的文件等资源。但是每个线程由自己独立的寄存器和栈,可以保证线程的控制流是独立的

image-20241130172134476

优点

  • 一个进程中可以有多个线程
  • 各个线程中可以并发的执行
  • 各个线程之间可以共享地址内存和文件等资源

缺点

  • 某一进程中的一个线程崩溃可能导致该进程内其他线程的的崩溃。
线程和进程的关系
  • 线程是依附于进程的,不能独立存在,它包含在进程之中,是进程中的实际运作单位。进程一旦结束,所有线程都结束。
  • 一个线程只能属于一个进程,而一个进程可以有多个线程,但至少有一个线程。
  • 线程是进程中的一个执行单元,由CPU独立调度执行,负责当前进程中任务的执行。一个进程可以有一个或多个线程,线程会拥有自己的堆栈和局部变量(不共享),但是它与同一进程中的多个线程将共享程序的内存空间,也就是该进程中的代码段(代码和常量),数据段(全局变量和静态变量),扩展段(堆存储)等系统资源。
线程的上下文切换

线程和进程最大的区别在于:线程是调度的基本单位,而进程则是资源拥有的基本单位

  • 在一个进程中如果只有一个线程,那么可以吧这个进程当作一个线程
  • 当进程拥有多个线程是,这些线程会共享相同的虚拟内存和全局变量等资源,这些资源在上下文切换的时候是不需要修改的。

那我们线程的上下文切换是需要保存那些内容呢?

  1. 如果在同一进程下

    那么切换的时候,只用切换线程的私有数据,比方说寄存器等不共享的数据

  2. 如果不在同一进程下

    那么他的上下文切换和进程上下文一样

所以线程的上下文切换相比进程,开销要小很多,所以我们有了多线程的优点

线程和进程的优缺点

多任务既可以由多进程实现,也可以由单进程内的多线程实现,还可以混合多进程+多线程。混合多进程和多线程的程序涉及到同步、数据共享的问题,这种模型更复杂,实际很少采用。
和多进程相比,多线程的优势在于:

  • 线程的调度与切换比进程快很多,同时创建一个线程的开销也比进程要小很多;
    线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,线程间通信就是读写同一个变量,速度很快。而进程之间的通信需要以通信的方式(Inter Process Communication,IPC)进行。

而多进程的优点在于:

  • 多进程程序更健壮,在多进程的情况下,一个进程崩溃不会影响其他进程,而在多线程的情况下,任何一个线程崩溃会直接导致整个进程崩溃。

小结

笔者这篇文章简单介绍了有关线程和进程的内容,笔者才疏学浅,如有纰漏还请不吝指出。以及笔者对于调度的内容还没有进行一个学习,之后学习会补充上去,接下来才可以方便我们理解iOS中GCD各个函数的一个意义。
参考博客:
【iOS】—— 多线程编程八重曲之(一)- 多线程基础
进程管理

相关文章:

【iOS】多线程基础

【iOS】多线程基础 文章目录 【iOS】多线程基础前言进程与线程进程进程的状态进程的一个控制结构进程的上下文切换 线程为什么要用线程什么是线程线程和进程的关系线程的上下文切换 线程和进程的优缺点 小结 前言 笔者由于对于GCD不是很了解,导致了项目中网络请求哪…...

常用网站网址

目录 1.docker hub2.csdn 1.docker hub https://image.cgdcgd.cc/ 2.csdn https://www.csdn.net/ ​...

go语言切片

切片 切片是一种数据结构,这种数据结构便于使用和管理数据集合。切片是围绕动态数组的概念构建的,可以按需自动增长和缩小。切片的动态增长是通过内置函数 append 来实现的。这个函数可以快速且高效地增长切片。还可以通过对切片再次切片来缩小一个切片的…...

鸿蒙NEXT元服务:利用App Linking实现无缝跳转与二维码拉起

【效果】 元服务链接格式(API>12适用):https://hoas.drcn.agconnect.link/ggMRM 【参考网址】 使用App Linking实现元服务跳转:文档中心 草料二维码:草料二维码生成器 【引言】 本文将详细介绍如何使用App Lin…...

网络药理学之薛定谔Schrödinge Maestro:6、分子对接(Glide、Ligand docking)和可视化

本人是win11,薛定谔版本是12.9。 官网:https://www.schrodinger.com/ 本篇文章的示例大分子蛋白PDB ID为4KNN,小分子配体的MOL ID为MOL004004。 本文部分图源来自知乎https://zhuanlan.zhihu.com/p/416698194,推荐为原作者贡献阅读…...

已解决ModuleNotFoundError: No module named ‘selenium‘

1. 错误提示 ModuleNotFoundError: No module named selenium,这意味着你试图导入一个名为 selenium 的模块,但Python找不到这个模块 2. 解决方案 安装缺失的模块: 如果你确定模块名称正确但仍然收到这个错误,那么可能是你没有安装这个模块…...

【Maven】依赖冲突如何解决?

准备工作 1、创建一个空工程 maven_dependency_conflict_demo,在 maven_dependency_conflict_demo 创建不同的 Maven 工程模块,用于演示本文的一些点。 什么是依赖冲突? 当引入同一个依赖的多个不同版本时,就会发生依赖冲突。…...

什么是EMS

EMS是能量管理系统(Energy Management System)的缩写,是一种集成的技术解决方案,旨在帮助企业和组织更有效地管理和优化其能源使用。EMS通过收集、分析和报告能源数据来识别节能机会,并提供工具以实施改进措施。 主要…...

26页PDF | 数据中台能力框架及评估体系解读(限免下载)

一、前言 这份报告详细解读了数据中台的发展历程、核心概念、能力框架及成熟度评估体系。它从阿里巴巴的“大中台,小前台”战略出发,探讨了数据中台如何通过整合企业内部的数据资源和能力,加速业务迭代、降低成本,并推动业务增长…...

【Vue3】【Naive UI】< a >标签

【Vue3】【Naive UI】< a >标签 超链接及相关属性其他属性 【VUE3】【Naive UI】&#xff1c;NCard&#xff1e; 标签 【VUE3】【Naive UI】&#xff1c;n-button&#xff1e; 标签 【VUE3】【Naive UI】&#xff1c;a&#xff1e; 标签 <a> 标签HTML中的一个锚&…...

分页查询日期格式不对

方式一:在属性上加入注解&#xff0c;对日期进行格式化 方式二:在 WebMvcConfiguration 中扩展Spring MVC的消息转换器&#xff0c;统一对日期类型进行格式化处理 /*** 统一转换处理扩展spring mvc* 后端返回前端的进行统一转化处理* param converters*/Overrideprotected voi…...

DAY140权限提升-Linux系统权限提升篇VulnhubPATH变量NFS服务Cron任务配合SUID

一、演示案例-Linux系统提权-Web&普通用户-SUID-NFS安全 NFS是一种基于TCP/IP 传输的网络文件系统协议&#xff0c;通过使用NFS协议&#xff0c;客户机可以像访问本地目录一样访问远程服务器中的共享资源。 https://www.virtualbox.org/wiki/Downloads https://www.vuln…...

HTTPS 的应用数据是如何保证完整性的?

在 HTTPS 中&#xff0c;确保 应用数据的完整性 是通过以下几个关键机制来实现的&#xff1a; 消息认证码&#xff08;MAC&#xff09;&#xff1a;用于确保数据在传输过程中未被篡改。加密&#xff1a;通过加密数据防止数据被窃取&#xff0c;并与 MAC 配合使用&#xff0c;确…...

Unity ShaderLab 实现3D物体描边

实现思路&#xff1a; 给物体添加第二个材质球&#xff0c;在shader的顶点着色器中使顶点的位置变大&#xff0c;然后在片元着色器中输出描边颜色。 shader Graph实现如下&#xff1a; ShaderLab实现如下&#xff1a; Shader "Custom/Outline" {Properties{[HDR]_…...

SQL进阶——C++与SQL进阶实践

在C开发中&#xff0c;SQL数据库的操作是开发者常见的任务之一。虽然前面我们已经介绍了如何在C中通过数据库连接执行基本的SQL查询&#xff0c;但在实际项目中&#xff0c;我们通常需要更加复杂和高效的数据库操作。存储过程与函数的调用、复杂SQL查询的编写、以及动态构造SQL…...

AIGC--------AIGC在医疗健康领域的潜力

AIGC在医疗健康领域的潜力 引言 AIGC&#xff08;Artificial Intelligence Generated Content&#xff0c;人工智能生成内容&#xff09;是一种通过深度学习和自然语言处理&#xff08;NLP&#xff09;等技术生成内容的方式。近年来&#xff0c;AIGC在医疗健康领域展现出了极…...

node.js中实现MySQL的增量备份

有时候&#xff0c;我们需要对生产库进行备份&#xff0c;不要求实时性很高&#xff0c;大概每天一次就行&#xff0c;为性能考虑&#xff0c;只备份最新更改内容&#xff0c;即增量备份即可&#xff0c;这种场景下对DB的设计和备份语句有所要求。 首先要求按源表各字段定义目标…...

Java线程池提交任务流程底层源码与源码解析

前言 嘿&#xff0c;各位技术爱好者们&#xff0c;今天咱们来聊聊Java线程池提交任务的底层源码与源码解析。作为一个资深的Java开发者&#xff0c;我相信你一定对线程池并不陌生。线程池作为并发编程中的一大利器&#xff0c;其重要性不言而喻。今天&#xff0c;我将以对话的…...

新型大语言模型的预训练与后训练范式,Meta的Llama 3.1语言模型

前言&#xff1a;大型语言模型&#xff08;LLMs&#xff09;的发展历程可以说是非常长&#xff0c;从早期的GPT模型一路走到了今天这些复杂的、公开权重的大型语言模型。最初&#xff0c;LLM的训练过程只关注预训练&#xff0c;但后来逐步扩展到了包括预训练和后训练在内的完整…...

硬菜3道+馒头

硬菜3道 1、可乐鸡翅 》鸡翅滑刀酱油耗油胡椒粉盐》 搅拌腌制3-5分钟 》油锅&#xff0c;直到2面煎黄 》倒入可乐&#xff0c;到大火收汁&#xff0c;出锅 2、洋葱牛肉 》冻牛肉切薄酱油耗油胡椒粉盐 》手指摇匀 》加入生粉水&#xff0c;继续摇匀》直到粘稠 》油锅牛肉炒半熟&…...

label-studio的使用教程(导入本地路径)

文章目录 1. 准备环境2. 脚本启动2.1 Windows2.2 Linux 3. 安装label-studio机器学习后端3.1 pip安装(推荐)3.2 GitHub仓库安装 4. 后端配置4.1 yolo环境4.2 引入后端模型4.3 修改脚本4.4 启动后端 5. 标注工程5.1 创建工程5.2 配置图片路径5.3 配置工程类型标签5.4 配置模型5.…...

利用ngx_stream_return_module构建简易 TCP/UDP 响应网关

一、模块概述 ngx_stream_return_module 提供了一个极简的指令&#xff1a; return <value>;在收到客户端连接后&#xff0c;立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量&#xff08;如 $time_iso8601、$remote_addr 等&#xff09;&a…...

K8S认证|CKS题库+答案| 11. AppArmor

目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作&#xff1a; 1&#xff09;、切换集群 2&#xff09;、切换节点 3&#xff09;、切换到 apparmor 的目录 4&#xff09;、执行 apparmor 策略模块 5&#xff09;、修改 pod 文件 6&#xff09;、…...

OpenLayers 分屏对比(地图联动)

注&#xff1a;当前使用的是 ol 5.3.0 版本&#xff0c;天地图使用的key请到天地图官网申请&#xff0c;并替换为自己的key 地图分屏对比在WebGIS开发中是很常见的功能&#xff0c;和卷帘图层不一样的是&#xff0c;分屏对比是在各个地图中添加相同或者不同的图层进行对比查看。…...

聊一聊接口测试的意义有哪些?

目录 一、隔离性 & 早期测试 二、保障系统集成质量 三、验证业务逻辑的核心层 四、提升测试效率与覆盖度 五、系统稳定性的守护者 六、驱动团队协作与契约管理 七、性能与扩展性的前置评估 八、持续交付的核心支撑 接口测试的意义可以从四个维度展开&#xff0c;首…...

大数据学习(132)-HIve数据分析

​​​​&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

Razor编程中@Html的方法使用大全

文章目录 1. 基础HTML辅助方法1.1 Html.ActionLink()1.2 Html.RouteLink()1.3 Html.Display() / Html.DisplayFor()1.4 Html.Editor() / Html.EditorFor()1.5 Html.Label() / Html.LabelFor()1.6 Html.TextBox() / Html.TextBoxFor() 2. 表单相关辅助方法2.1 Html.BeginForm() …...

Proxmox Mail Gateway安装指南:从零开始配置高效邮件过滤系统

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐&#xff1a;「storms…...

TJCTF 2025

还以为是天津的。这个比较容易&#xff0c;虽然绕了点弯&#xff0c;可还是把CP AK了&#xff0c;不过我会的别人也会&#xff0c;还是没啥名次。记录一下吧。 Crypto bacon-bits with open(flag.txt) as f: flag f.read().strip() with open(text.txt) as t: text t.read…...