【iOS】多线程

news2024/12/27 19:02:10

文章目录

  • 前言
  • 一、多线程的选择方案
  • 二、GCD和NSOperation的比较
  • 二、多线程相关概念
    • 任务
    • 队列
  • 三、死锁情况
    • 主队列加同步任务
  • 四、任务队列组合
    • 主队列+异步
    • 并发队列+异步


前言

这两天将iOS的多线程的使用都看了一遍,iOS的多线程方案有许多,本篇博客主要总结一下不同方案之间的区别以及面试一般会问到的问题

一、多线程的选择方案

技术方案简介语言线程生命周期使用频率
pthread一套通用的多线程API,适用于Unix/Linux/Windows等系统,跨平台/可移植,使用难度大C程序员管理几乎不用
NSThreadNSThread是苹果官方提供的,使用起来更加面向对象,简单易用,可以直接操作线程对象OC程序员管理几乎不用
GCD旨在替代NSThread等线程技术充分利用设备的多核C自动管理经常使用
NSOperation基于GCD的更高一层封装OC自动管理经常使用

二、GCD和NSOperation的比较

关系:
GCD面向底层C语言的API
NSOperation使用GCD进行封装的

对比

  • GCD是苹果官方推荐的多线程方案,使用起来比较方便,更加轻量级
  • GCD只支持FIFO的队列,NSOperation可以设置最大并发数控制串行并行以及通过添加依赖关系来调整执行顺序,这些都是GCD做不到的
  • NSOpration甚至可以跨队列设置依赖关系,但是GCD只能通过设置串行队列,或者在队列内添加barrier任务才能控制执行顺序,较为复杂
  • NSOperation支持KVO(面向对象)可以检测operation是否正在执行、是否结束、是否取消
- (void)viewDidLoad {
    [super viewDidLoad];
    
    self.operationQueue = [[NSOperationQueue alloc] init];
    
    [self.operationQueue addObserver:self
                          forKeyPath:@"operations"
                             options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                             context:NULL];
}

二、多线程相关概念

任务

就是执行的操作,比如GCD中的Block。
执行任务有两种方式:同步执行与异步执行

同步执行(sync):

  • 同步添加任务到指定的队列中,在添加的任务结束之前线程会一直等待,无法执行其他操作
  • 只能在当前线程中执行任务,不具备开启新线程的能力。

异步执行(async):

  • 异步添加任务到指定的队列中,它不会做任何等待,添加后立即返回不会阻塞线程、可以继续执行任务.
  • 可以在新的线程中执行任务,具备开启新线程的能力。

这样子来看可能比较抽象,我们用代码层面来理解就是:

进入dispatch_sync函数后程序不会立刻返回,因此会阻塞线程
而进入dispatch_async函数后程序会立刻返回,不会妨碍进行下一步操作

队列

这里的队列指执行任务的等待队列,即用来存放任务的队列。队列是一种特殊的线性表,采用 FIFO(先进先出)的原则。GCD 中有两种队列串行队列和并发队列。两者都符合 FIFO(先进先出)的原则。两者的主要区别是:执行顺序不同,以及开启线程数不同。

  • 串行队列(Serial Dispatch Queue):每次只有一个任务被执行。让任务一个接着一个地执行。(只开启一个线程,一个任务执行完毕后,再执行下一个任务
  • 并发队列(Concurrent Dispatch Queue):可以让多个任务并发(同时)执行。(可以开启多个线程,并且同时执行任务

三、死锁情况

主队列加同步任务

- (void)syncTaskWithMain {
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    dispatch_sync(mainQueue, ^{
        NSLog(@"2---%@", [NSThread currentThread]); // 打印当前线程
        NSLog(@"任务2");
    });
}

// 在主线程中调用 syncTaskWithMain
- (void)viewDidLoad {
    [super viewDidLoad];
    [self syncTaskWithMain];
}

在上述代码中,我们在主线程的viewDidLoad方法中调用了asyncTaskWithMain函数,而在asyncTaskWithMain函数中,我们使用dispatch_sync向主队列提交了一个同步任务。
这种情况会导致死锁,原因如下:

  1. [self syncTaskWithMain]被调用时,主线程进入了asyncTaskWithMain函数。
  2. asyncTaskWithMain函数中,dispatch_sync函数会等待主队列空闲,然后在主队列中同步执行提交的任务。
  3. 但是,由于主线程正在执行syncTaskWithMain函数,所以主队列被占用,无法空闲。
  4. 因此,dispatch_sync函数会一直等待主队列空闲,而主线程也会一直被阻塞在syncTaskWithMain函数中,从而导致死锁。

为了避免死锁,我们应该在syncTaskWithMain函数中使用dispatch_async函数向主队列提交异步任务,或者在其他串行队列中使用dispatch_sync函数提交同步任务。

也就是二者相互等待造成死锁

四、任务队列组合

在这里插入图片描述
也就是只有当异步才会开辟新线程

主队列+异步

这里需要注意的一点是主队列+异步不会开辟新线程,这是由主队列的特性决定的

主队列+异步时既不会创建新的线程,也不会阻塞线程,我们来分析一下原因

主队列(Main Dispatch Queue)
主队列是一个特殊的串行队列,它在应用的主线程上执行任务。由于它是串行的,它一次只能执行一个任务。这意味着如果你在主队列上使用 dispatch_async 来提交一个任务,这个任务会被放到队列的末尾等待执行。

为什么不会创建新的线程
使用 dispatch_async 将任务提交到主队列时,这些任务不会创建新线程,因为:

  • 主队列特性:
    主队列绑定于主线程,所有在主队列上提交的任务都必须在主线程上执行。这是由于主线程通常处理所有的 UI 更新和用户交互,所以系统保证主队列的任务在主线程上顺序执行。
  • 任务调度:
    dispatch_async 函数只是将任务异步地放入队列中,它本身不关心任务的执行在哪个线程进行,任务的执行线程完全取决于队列的性质。由于主队列特性,即使使用 dispatch_async,任务仍然会在主线程上执行

为什么不会导致阻塞
使用 dispatch_async 提交任务到主队列时,不会阻塞主线程,原因包括:

  • 异步执行:
    dispatch_async 是异步执行的,这意味着它会立即返回,不会等待任务执行完成。因此,即使任务最终在主线程上执行,dispatch_async 本身也不会阻塞主线程。
  • 执行时机:
    由于主队列是串行队列,提交到主队列的异步任务会在先前的任务完成后按顺序执行。如果主线程当前正在处理其他任务(如用户输入、动画等),那么主队列上的任务会等待直到主线程空闲。

也就是当主线程的所有的原先的任务都执行完后才回去执行添加到主队列中的异步任务

-(void)asyncTaskWithMain{
    NSLog(@"currentThread---%@",[NSThread currentThread]);
    dispatch_queue_t q = dispatch_get_main_queue();
    dispatch_async(q, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
        NSLog(@"任务1");
    });
    NSLog(@"4");
}

// viewC
    [self asyncTaskWithMain];
    NSLog(@"等待");
    NSLog(@"等待");
    NSLog(@"等待");
    NSLog(@"等待");

输出:
在这里插入图片描述

并发队列+异步

同时如果是全局并发队列+异步,那么不会等待主队列任务执行完毕,两个线程会同时执行任务

    dispatch_queue_t globalQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
    dispatch_async(globalQueue, ^{
        NSLog(@"1---%@",[NSThread currentThread]);
        NSLog(@"任务1");
    });

输出:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1647309.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ctfshow web入门 php序列化 web260--web266

web260 正则看序列化之后的ctfshow有没有ctfshow_i_love_36D 直接传就行了 web261 code0x36d弱比较直接写877a或者877.php都行的<?php class ctfshowvip{public $username;public $password;public function __construct(){$this->username$u877.php;$this->pass…

安卓手机原生运行 ARM Ubuntu 24.04 桌面版(一)

本篇文章&#xff0c;聊一聊尝试让安卓手机原生运行 Ubuntu&#xff0c;尤其是运行官方未发布过的 ARM 架构的 Ubuntu 24.04 桌面版本。 写在前面 最近的几篇文章&#xff0c;都包含了比较多的实操内容、需要反复的复现验证&#xff0c;以及大量的调试过程&#xff0c;为了不…

【StarRocks系列】 Trino 方言支持

我们在之前的文章中&#xff0c;介绍了 Doris 官方提供的两种方言转换工具&#xff0c;分别是 sql convertor 和方言 plugin。StarRocks 目前同样也提供了类似的方言转换功能。本文我们就一起来看一下这个功能的实现与 Doris 相比有何不同。 一、Trino 方言验证 我们可以通过…

opencv图片的旋转-------c++

图片的旋转 /// <summary> /// 图片的旋转 /// </summary> /// <param name"img"></param> /// <param name"angle">旋转角度:正数&#xff0c;则表示逆时针旋转;负数&#xff0c;则表示顺时针旋转</param> /// <…

Java | Leetcode Java题解之第73题矩阵置零

题目&#xff1a; 题解&#xff1a; class Solution {public void setZeroes(int[][] matrix) {int m matrix.length, n matrix[0].length;boolean flagCol0 false;for (int i 0; i < m; i) {if (matrix[i][0] 0) {flagCol0 true;}for (int j 1; j < n; j) {if (…

亏了亏了!双向孟德尔随机化阴性结果居然发了SCI二区(IF=6.7)

‍ 今天为诸位介绍的这篇文章是一项双向孟德尔随机化研究&#xff08;MR&#xff09;&#xff0c;惊讶的是&#xff0c;双向因果均为阴性结果发了SCI二区&#xff01;我们一起来看看&#xff01; 2024年4月17日&#xff0c;广东医科大学附属医院的学者做了一项双向两样本孟德尔…

为antd design vue组件库中的表格添加斑马线、鼠标悬浮表格中字体转变颜色的效果

前言&#xff1a; 在公司完成UI设计稿时&#xff0c;需要实现antd design vue组件库中的表格展示斑马线样式&#xff0c;同时具有鼠标悬浮表格中字体转变颜色的效果&#xff0c;经过多次尝试&#xff0c;最终实现&#xff0c;总结如下&#xff1a; <style lang"scss&q…

cmd输入mysql -u root -p无法启动

问题分析&#xff1a;cmd输入mysql -u root -p无法启动 解决方法&#xff1a;配置系统环境变量 1.找到mysql安装文件下的bin文件&#xff1a;&#xff08;复制改文件地址,如下图所示&#xff09; 2.电脑桌面下方直接搜索环境变量并进入&#xff0c;如下图 3.点击环境变量&a…

第八节课《大模型微调数据构造》

大模型微调数据构造&#xff08;补充课程&#xff09;_哔哩哔哩_bilibili Tutorial/FineTune at main Focusshang/Tutorial GitHub 一、大模型训练数据介绍 预训练&#xff1a; 网络、论文数据&#xff0c;无标签数据transform算法base model典型&#xff1a;GPT监督微调 对…

软件系统安全设计规范(word原件)

1.1安全建设原则 1.2 安全管理体系 1.3 安全管理规范 1.4 数据安全保障措施 1.4.1 数据库安全保障 1.4.2 操作系统安全保障 1.4.3 病毒防治 1.5安全保障措施 1.5.1实名认证保障 1.5.2 接口安全保障 1.5.3 加密传输保障 1.5.4终端安全保障 软件资料清单列表部分文档…

nginx自动部署-跨操作系统

项目里面有一个需求&#xff0c;就是需要用让nginx进程提供给系统管理一个start,stop和getPid方法&#xff0c;这样系统管理可以自动拉起来nginx&#xff0c;达到自动部署的目的。离线部署同样适用 这样一来&#xff0c;我就需要提供windows版本linux不同版本的nginx源码包&am…

Git -- reset 详解

引言 当我们在项目中有多个人协同开发时候&#xff0c;难免会出现一些错误的提交或者删除了一些重要文件。我们需要回滚到指定的某一个节点。那些乱七八糟的各种提交都要清除掉。 这时候&#xff0c;我们的指令就要用到了。reset 正文 git reset。它的一句话概括 git-reset …

Java设计模式 _结构型模式_享元模式

一、享元模式 1、享元模式 享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型模式。主要用于减少创建对象的数量&#xff0c;以减少内存占用和提高性能。主要解决有大量对象时&#xff0c;有可能会造成内存溢出&#xff0c;我们把其中共同的部分抽象出来&#x…

【C语言】整数,浮点数数据在内存中的存储

Tiny Spark get dazzling some day. 目录 1. 整数在内存中的存储1.1 原码、反码、补码1.1 大小端存储1.2.1 字节序分类1.2.2 判断字节序 2. 浮点数在内存中的存储2.1 浮点数的存储形式2.2 浮点数的 “ 存 ”2.2.1 S2.2.2 E2.2.3 F 2.3 浮点数的 “ 取 ”2.3.1 S2.3.2 E、F 3. 浮…

Docker重启容器失败

Bug描述 [rootVM-12-15-centos ~]# docker restart ca1008fbdf25 Error response from daemon: Cannot restart container ca1008fbdf25: driver failed programming external connectivity on endpoint nginx_java (aded2fc7cbfa784b2e6a39e08d3ae2e7d00c13af88879a8fe7c5007…

软件2班20240506

package com.yanyu;public interface JDBC {void getConnection(); }package com.yanyu;public class Mysql implements JDBC{// ALT ENTER // ctrl o 专门 针对 写 父类方法的Overridepublic void getConnection() {System.out.println("正在 了解…

专家解读 | NIST网络安全框架(1):框架概览

随 着信息技术的快速发展&#xff0c;组织面临着越来越严峻的网络安全挑战。NIST网络安全框架&#xff08;NIST Cybersecurity Framework&#xff0c;CSF&#xff09;是一个灵活的综合性指南&#xff0c;旨在协助各类组织建立、改进和管理网络安全策略&#xff0c;以加强网络安…

流畅的python-学习笔记_符合python风格的对象

对象表示形式 查看对象说明&#xff0c;可以通过__repr__和__str__方法&#xff0c;前者主要用于开发者&#xff0c;后者主要用于用户&#xff0c;这两个方法分别对内置函数repr和str函数提供支持 向量类 备选构造方法 classmethod和staticmethod staticmethod用的不是特别…

yum仓库和NFS网络共享服务

一、yum 1.1yum的定义 yum是一个基于RPM包&#xff0c;构建的软件更新机制&#xff0c;能够自动解决软件包之间的依赖关系。解决了日常工作中的大量查找安装依赖包的时间 为什么会有依赖关系的发生 因为linux本身就是以系统简洁为自身优势&#xff0c;所以在安装操作系统的时…

南京观海微电子---电源,从微观角度观看电功率是怎么产生

从微观角度看看无功功率是怎么产生的&#xff0c;在此之前&#xff0c;我们得先知道引起无功功率的元器件是储能器件&#xff0c;主要是电感和电容。 首先&#xff0c;在宏观上&#xff0c;我们知道电感能导致电压超前电流90&#xff0c;可从如下公式推出&#xff1a; 由此可以…