iOS - 多线程-GCD

news2024/11/16 7:53:16

文章目录

  • iOS - 多线程-GCD
    • 1. 常见多线程方案
    • 2. GCD
      • 2.1 GCD的常见函数
        • GCD中有2个用来执行任务的函数
      • 2.2 GCD的队列
        • 2.2.1 GCD的队列可以分为2大类型
      • 2.3 容易混淆的术语
        • 2.4.1 有4个术语比较容易混淆:`同步、异步`、`并发、串行`
      • 2.4 各种队列的执行效果
    • 3. 死锁
      • 3.1 死锁示例
      • 3.2 死锁分析
      • 3.3 其他示例
      • 3.3.1 interview02
      • 3.3.2 interview03
      • 3.3.3 interview04
    • 4. 案例
      • 4.1 案例1
      • 4.2 分析
    • 5. 拓展
      • GNUstep

iOS - 多线程-GCD

1. 常见多线程方案

NSThreadGCDNSOperation底层都依赖于pthread

2. GCD

2.1 GCD的常见函数

GCD中有2个用来执行任务的函数
  • 同步的方式执行任务
    dispatch_sync(dispatch_queue_t queue, dispatch_block_t block);

    1. queue:队列
    2. block:任务
  • 异步的方式执行任务
    dispatch_async(dispatch_queue_t queue, dispatch_block_t block);

  • GCD源码:https://github.com/apple/swift-corelibs-libdispatch

2.2 GCD的队列

2.2.1 GCD的队列可以分为2大类型
  • 并发队列(Concurrent Dispatch Queue)

    1. 可以让多个任务并发(同时)执行(自动开启多个线程同时执行任务)
    2. 并发功能只有在异步dispatch_async)函数下才有效
  • 串行队列(Serial Dispatch Queue)

    1. 让任务一个接着一个地执行(一个任务执行完毕后,再执行下一个任务)

2.3 容易混淆的术语

2.4.1 有4个术语比较容易混淆:同步、异步并发、串行
  • 同步异步主要影响:能不能开启新的线程

    • 同步:在当前线程中执行任务,不具备开启新线程的能力
    • 异步:在新的线程中执行任务,具备开启新线程的能力
  • 并发串行主要影响:任务的执行方式

    • 并发多个任务并发(同时)执行
    • 串行一个任务执行完毕后,再执行下一个任务

2.4 各种队列的执行效果

  • 使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列(产生死锁)

3. 死锁

3.1 死锁示例

// 问题:以下代码是在主线程执行的,会不会产生死锁?
NSLog(@"执行任务1");
dispatch_queue_t queue = dispatch_get_main_queue();
dispatch_sync(queue, ^{
   NSLog(@"执行任务2");
});
NSLog(@"执行任务3");

3.2 死锁分析

如上代码

  • 正常情况应该是顺序执行任务1任务2任务3
  • 任务2使用dispatch_sync同步执行方式,放入主线程队列,因此任务2需要排队等待前面的任务执行完成后才执行
  • 但是当前方法体viewDidLoad可以认为就是一个任务在执行,但是执行到任务2dispatch_sync处,会等待dispatch_sync执行完成再继续往下执行
  • 此时,相当于任务2等待当前执行任务执行完成,当前执行任务也在等待任务2执行完成,相互等待因此造成线程死锁

3.3 其他示例

3.3.1 interview02

- (void)interview02 {
    // 问题:interview01中的sync,改成 async。会不会产生死锁?不会!
    /* 打印日志:
        执行任务1
        执行任务3
        执行任务2
     */
    NSLog(@"执行任务1");
    dispatch_queue_t queue = dispatch_get_main_queue();
    dispatch_async(queue, ^{
        NSLog(@"执行任务2");
    });
    NSLog(@"执行任务3");
}

3.3.2 interview03

- (void)interview03 {
    // 会不会产生死锁?会!
    /*
     分析:
     执行任务2 后,同步等待任务2 执行,但是因为queue是串行的,所以会相互等待
     */
    NSLog(@"执行任务1");
    dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_SERIAL);
    dispatch_async(queue, ^{
        NSLog(@"执行任务2");
        dispatch_sync(queue, ^{
            NSLog(@"执行任务3");
        });
        NSLog(@"执行任务4");
    });
    NSLog(@"执行任务5");
}

3.3.3 interview04

- (void)interview04 {
    // interview03改为并发队列(DISPATCH_QUEUE_CONCURRENT),会不会死锁?不会!
    NSLog(@"执行任务1");
    dispatch_queue_t queue = dispatch_queue_create("myqueue", DISPATCH_QUEUE_CONCURRENT);
    dispatch_async(queue, ^{
        NSLog(@"执行任务2");
        dispatch_sync(queue, ^{
            NSLog(@"执行任务3");
        });
        NSLog(@"执行任务4");
    });
    NSLog(@"执行任务5");
}

4. 案例

4.1 案例1

如下代码打印什么:

- (void)test {
    NSLog(@"2");
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        NSLog(@"1");
        [self performSelector:@selector(test) withObject:nil afterDelay:0];
        NSLog(@"3");
    });
}

打印结果:

观察到,2不会打印

去掉dispatch_async又会怎么样

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    NSLog(@"1");
    [self performSelector:@selector(test) withObject:nil afterDelay:0];
    NSLog(@"3");
}


这时候都有打印,只不过打印顺序1>3>2

接着,回到dispatch_async里执行,但是把afterDelay去掉

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
    dispatch_async(queue, ^{
        NSLog(@"1");
        [self performSelector:@selector(test) withObject:nil];
        NSLog(@"3");
    });
}


打印结果是1>2>3,这次打印顺序是正常的

4.2 分析

上面的例子中,主要是考察runloop多线程的相关知识

  • 首先,在dispatch_async中使用- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;方法来执行,使用afterDelay:0看似是在没有延迟的情况下执行,实际上因为该方法是基于 runloop的,相当于往runloop添加一个定时器,但是因为此时我们是在子线程中执行的,子线程中的runloop默认不会开启,所以test方法没有执行。我们尝试开启runloop
dispatch_async(queue, ^{
    NSLog(@"1");
    [self performSelector:@selector(test) withObject:nil afterDelay:0];
    NSLog(@"3");
    
    [[NSRunLoop currentRunLoop] addPort:[[NSPort alloc]init] forMode:NSDefaultRunLoopMode];
    [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
});

可以看到,2打印了

  • 接着,我们去掉了dispatch_async,发现打印结果是1>3>2,为什么3会比2先打印的?
    使用afterDelay:0看似是在没有延迟的情况下执行,实际上因为该方法是基于 runloop的定时器,虽然没有延迟设置为 0,但是runloop的定时器是在被唤醒的时候处理定时器的,但是在进入休眠之前会处理完点击事件,因此看到的打印结果是13先打印,然后打印2

  • 最后,回到dispatch_async中执行,只不过使用的是- (id)performSelector:(SEL)aSelector withObject:(id)object;方法来执行,查看源码

    该方法实际是直接使用objc_msgSend方法执行,相当于我们直接[self test]这样调用方法,所以这时候打印顺序是正常的1>2>3

5. 拓展

GNUstep

GNUstep是GNU计划的项目之一,它将Cocoa的OC库重新开源实现了一遍

源码地址:https://gnustep.github.io/resources/downloads.html

虽然GNUstep不是苹果官方源码,但还是具有一定的参考价值

@oubijiexi

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

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

相关文章

鸿蒙开发模拟器的坑, No Devices

问题 我已经安装了模拟器&#xff0c;并且模拟器已经运行了 在Device Manager页面开启模拟器 No Devices 但是这里没有模拟器的选项 解决 添加环境变量 下面步骤 1、清除用户数据 2、 关闭Device Manager 3、 关闭ide 重启ide、开启模拟器 看到有模拟器的选项了

【数据结构|C语言版】算法效率和复杂度分析

前言1. 算法效率2. 大O的渐进表示法3. 时间复杂度3.1 时间复杂度概念3.2 时间复杂度计算举例 4. 空间复杂度4.1 空间复杂度的概念4.2 空间复杂度计算举例 5. 常见复杂度对比结语 ↓ 个人主页&#xff1a;C_GUIQU 个人专栏&#xff1a;【数据结构&#xff08;C语言版&#xff09…

光伏仿真设计需要用到的工具有哪些?

随着全球能源结构的转型和可持续发展战略的深入实施&#xff0c;光伏发电作为一种清洁、可再生的能源形式&#xff0c;正日益受到广泛关注和应用。在光伏系统的设计和优化过程中&#xff0c;光伏仿真设计工具发挥着至关重要的作用。那么&#xff0c;光伏仿真设计需要用到的工具…

Opencv_3_图像对象的创建与赋值

ColorInvert.h 如下&#xff1a; #include <opencv.hpp> using namespace std; #include <opencv.hpp> using namespace cv; using namespace std; class ColorInvert{ public : void mat_creation(); }; ColorInvert.cpp 文件如下&#xff1a; #include &q…

【oceanbase】安装ocp,ocp部署oceanbase

https://www.oceanbase.com/docs/common-ocp-1000000000584989 资源 iphostnamecpumem组件192.168.0.71obnode-000-071816oceanbase-ce192.168.0.72obnode-000-072816oceanbase-ce192.168.0.73obnode-000-073816oceanbase-ce192.168.0.74obproxy-000-07424obproxy-ce192.168.0…

springcloud Ribbon的详解

1、Ribbon是什么 Ribbon是Netflix发布的开源项目&#xff0c;Spring Cloud Ribbon是基于Netflix Ribbon实现的一套客户端负载均衡的框架。 2、Ribbon能干什么 LB负载均衡(Load Balance)是什么&#xff1f;简单的说就是将用户的请求平摊的分配到多个服务上&#xff0c;从而达…

Redis入门到通关之数据结构解析-ZipList

文章目录 ☃️概述☃️ZipListEntry☃️Encoding编码☃️ZipList的连锁更新问题☃️总结 欢迎来到 请回答1024 的博客 &#x1f353;&#x1f353;&#x1f353;欢迎来到 请回答1024的博客 关于博主&#xff1a; 我是 请回答1024&#xff0c;一个追求数学与计算的边界、时间与…

STM32H750外设ADC之模拟窗口看门狗

目录 概述 1 相关寄存器 2 功能描述 3 AWDx 标志和中断 4 模拟看门狗 1 4.1 模拟看门狗 1 说明 4.2 模拟看门狗通道选择 4.3 阀值选择 5 模拟看门狗 2和3 6 ADCx_AWDy_OUT 信号输出生成 6.1 功能介绍 6.2 输出信号案例 7 模拟看门狗 1、 2、 3 比较 概述 本文主…

深度学习从入门到精通—Transformer

1.绪论介绍 1.1 传统的RNN网络 传统的RNN&#xff08;递归神经网络&#xff09;主要存在以下几个问题&#xff1a; 梯度消失和梯度爆炸&#xff1a;这是RNN最主要的问题。由于序列的长距离依赖&#xff0c;当错误通过层传播时&#xff0c;梯度可以变得非常小&#xff08;消失…

MATLAB中左边的大括号最后一行为什么会留很大的空白——解决

看了一些帖子说改字体&#xff0c;但是并没有什么用&#xff0c;在此给出亲测有效的方法&#xff1a;改变矩阵的行间距 先说一下问题 上图中留有大块空白 **解决办法&#xff1a;**光标放在矩阵上 格式——矩阵——更改矩阵&#xff0c;在矩阵设置中选中“行高相等”&#xff…

基于Springboot的学生毕业离校系统

基于SpringbootVue的学生毕业离校系统的设计与实现 开发语言&#xff1a;Java数据库&#xff1a;MySQL技术&#xff1a;SpringbootMybatis工具&#xff1a;IDEA、Maven、Navicat 系统展示 用户登录 网站首页 离校流程 网站公告 留言反馈 后台登录 学生管理 教师管理 离校流程…

【UI】element-ui的el-dialog的遮罩层在模态框的前面bug

最近在写element ui 的时候使用dialog组件&#xff0c;偶然出现了这种情况 原因&#xff1a; 是因为遮罩层插入进了body标签下&#xff0c;z-index高于当前父元素。 解决&#xff1a;在el-dialog标签里加上:modal-append-to-body"false"就可以了。 饿了么官网文档&a…

Redis - Redisson tryLock 函数参数分析

这里有三个参数&#xff1a; waitTime&#xff1a;等待时间leaseTime&#xff1a;超时施放时间TimeUnit&#xff1a;时间单位 等待时间 如果 ABC… 多个线程去抢夺一把锁&#xff0c;A 成功了&#xff0c;如果设置的是 -1&#xff0c;那么 BCD... 就不等待&#xff0c;直接返…

虚拟化+Docker基本管理

一、虚拟化简介 1、云端 华为云、谷歌云、腾讯云、阿里云、亚马逊、百度云、移动云、天翼云、西部数码云等 1.国内云 华为云、阿里云、腾讯云、天翼云(私有云) 2.国外云 谷歌云、亚马逊 2、云计算的服务模式是分层的 IaaS&#xff1a;Infrastructure&#xff08;基础设…

蓝桥杯第17169题——兽之泪II

问题描述 在蓝桥王国&#xff0c;流传着一个古老的传说&#xff1a;在怪兽谷&#xff0c;有一笔由神圣骑士留下的宝藏。 小蓝是一位年轻而勇敢的冒险家&#xff0c;他决定去寻找宝藏。根据远古卷轴的提示&#xff0c;如果要找到宝藏&#xff0c;那么需要集齐 n 滴兽之泪&#…

【YOLOv8改进[注意力]】YOLOv8添加DAT(Vision Transformer with Deformable Attention)助力涨点

目录 一 DAT 二 YOLOv8添加DAT助力涨点 1 总体修改 2 配置文件 3 训练 其他 一 DAT 官方论文地址&#xff1a;https://openaccess.thecvf.com/content/CVPR2022/papers/Xia_Vision_Transformer_With_Deformable_Attention_CVPR_2022_paper.pdf Transformers最近在各种视…

js连接抖音打印组件实现打印

js连接抖音打印组件实现打印小票 安装抖音打印组件 抖音打印组件文档&#xff1a; https://bytedance.larkoffice.com/docs/doccn2vbOOdd3KWrCd6Z93nIlvg 跟着文档案例一步步配基本上没问题&#xff0c; 打印的时候需要设置下打印机名称 export class DouyinPrint {construct…

完美运营版商城/拼团/团购/秒杀/积分/砍价/实物商品/虚拟商品等全功能商城

源码下载地址&#xff1a;完美运营版商城.zip 后台可以自由拖曳修改前端UI页面 还支持虚拟商品自动发货等功能 挺不错的一套源码 前端UNIAPP 后端PHP 一键部署版本

【计算机组成原理】浮点运算方法和浮点运算器

浮点加法、减法运算 浮点数加减法的步骤结合题目分析步骤 浮点数加减法的步骤 ① 0 操作数检查 ② 比较阶码大小&#xff0c;完成对阶 ③ 尾数进行加减法运算 ④ 结果规格化 ⑤ 舍入处理 ⑥ 判断结果是否溢出 结合题目分析步骤 例&#xff1a;设 x 2010 0.11011011&#x…

展商企业【广东伟创科技开发有限公司】| 2024水科技大会暨技术装备成果展

企业介绍 广东伟创科技开发有限公司成立于2006年&#xff0c;位于广东省江门市。公司是华南理工大学造纸与污染控制国家工程研究中心科技成果转化单位&#xff1b;是华南理工大学产学研合作单位&#xff1b;是广东省高新技术企业&#xff1b;是江门市现代信息服务业重点企业&am…