【iOS】—— Runloop和多线程问题总结

news2024/11/26 4:52:48

Runloop和多线程问题总结

    • runloop总结
      • 1. runloop简介
      • 2. runloop的基本作用
      • 3. 获取runloop的流程
      • 4. runloop和线程的关系
      • 5. runloop中的Mode有几种以及作用
      • 6.runloop的事件源
      • 7. 讲一下source0和source1
      • 8. runloop的六种观察者模式
      • 9. 针对定时器在滑动时停止工作的问题
      • 10. 如何解决定时器不准确的原因
      • 11. 什么是常驻线程,线程保活
    • 多线程
      • 1. 队多线程的理解
        • 好处
        • 坏处
      • 2. iOS多线程的方式有哪几种
      • 3. 有用过GCD吗
      • 4. GCD的队列类型
      • 5. NSOperationQueue和GCD的区别以及优势
        • 区别:
      • 6. 线程安全的处理手段

runloop总结

1. runloop简介

runloop是一种高级的循环机制,让程序持续运行,并处理程序中的事件,让线程在需要的时候忙起来,不需要的时候休眠。

主线程的runloop保证应用程序的存活,从而可以实时接收到用户的响应,能够触发事件。

2. runloop的基本作用

保持程序持续运行,节省CPU资源,提高程序性能。

3. 获取runloop的流程

程序开始时第一次获取runloop的时候,一定获取的是主线程的runloop。在获取runloop的函数中会定义一个全局的字典变量,该字典是以线程为key,获取的runloopvalue,保存到字典中。方便之后获取runloop的时候可以先遍历字典找一找之前有没有获取。如果字典没有对应的runloop,再获取对应线程的runloop

4. runloop和线程的关系

  1. 每条线程都有唯一与之对应的runloop对象。
  2. 线程刚创建的时候,并没有runloop对象,runloop会在第一次获取它的时候创建。
  3. 主线程默认开启自动开启runloop,子线程需要手动获取对应的runloop
  4. 当线程结束之后,runloop也会随之销毁。

5. runloop中的Mode有几种以及作用

runloop中有5种Mode:

  • NSDefaultRunLoopMode app默认的Mode,主线程就在这个状态下运行。
  • UITrackingRunLoopMode 界面跟踪,用于scrollview的触摸滑动,保证界面不会受其他Mode的影响。
  • UIInitializationRunLoopMode:在程序刚启动的时候进入的第一个Mode,然后就切换到NSDefaultRunLoopMode
  • kCFRunLoopCommonModes 这是一种标记Mode,事件可以运行在所有标记的Mode中,也可以添加观察者。
  • GSEventReceiveRunLoopMode: 接受系统事件的内部 Mode,通常用不到。

一个RunLoop包含若干个Mode,每个Mode又包含若干个Source/Timer/Observer

在这里插入图片描述

常用的有三种Mode:

  • NSDefaultRunLoopMode, 默认的模式, 有事件响应的时候, 会阻塞旧事件。
  • NSRunLoopCommonModes, 普通模式, 不会影响任何事件。
  • UITrackingRunLoopMode, 只能是有事件的时候才会响应的模式。

6.runloop的事件源

输入源:通常用于处理基于文件描述符的事件,可以将外部事件与runloop关联起来,使runloop可以监听这些事件,并且进行相应的处理。

定时源:用于在指定时间间隔触发事件,适用于需要定期执行的任务。通过定时器在特定的时间触发回调方法。

7. 讲一下source0和source1

source0source1都属于CFRunLoopSourceRef,而CFRunLoopSourceRef是对于输入事件源的抽象。

source0source1都是在runloop中描述事件的触发机制。source0用于处理手动触发的事件,source1用于处理系统或者其他线程之间的事件。

source0(不会唤醒runloop):

  • source0是非基于端口的事件源,用于处理应用程序内部生成的事情。
  • 通常响应和处理一些特定的应用程序级事件,例如:触摸事件,用户交互事件。
  • source0事件通常由应用程序自身生成和处理,不涉及线程间通信。

source1(会唤醒runloop):

  • source1是基于端口的事件源,用于处理与其他进程或者内核之间的交互
  • 通常处理一些系统级事件,如:网络数据,定时器事件。
  • source1事件的处理涉及与其他进程或内核的通信,比如进行网络数据的读写、处理文件描述符的状态变化等。

示例:

用户用手指点击app界面时,会先触摸到硬件,屏幕会将这个事件先包装成EventEvent先告诉source1(mach_port)唤醒runloop,然后将这个事件Event分发给source0,让source0处理该事件。

8. runloop的六种观察者模式

//观测的时间点有一下几个
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
    kCFRunLoopEntry = (1UL << 0),   //   即将进入RunLoop
    kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理Timer
    kCFRunLoopBeforeSources = (1UL << 2), // 即将处理Source
    kCFRunLoopBeforeWaiting = (1UL << 5), //即将进入休眠
    kCFRunLoopAfterWaiting = (1UL << 6),// 刚从休眠中唤醒
    kCFRunLoopExit = (1UL << 7),// 即将退出RunLoop
    kCFRunLoopAllActivities = 0x0FFFFFFFU
};

9. 针对定时器在滑动时停止工作的问题

  1. 在创建定时器的时候,并且不做任何操作的时候,定时器处于NSDefaultRunLoopMode下。
  2. 当按住鼠标拖拽视图的时候,runloop就结束了NSDefaultRunLoopMode,切换到UITrackingRunLoopMode,但是在这个模式下,并没有添加NSTimer,所以定时器就不工作了。
  3. 松开鼠标的时候,runloop就结束UITrackingRunLoopMode模式,回到NSDefaultRunLoopMode模式,NSTimer就开始工作了。

10. 如何解决定时器不准确的原因

  1. runloop的循环过程中,NSTimer的触发事件阻塞,导致循环不能进行,延误了NSTimer的触发时间。
  2. runloop的循环过程中,主线程在某一时刻发生阻塞,导致循环不能进行,延误了NSTimer的触发时间。
  3. 切换了runloop的运行模式,导致NSTimer在原有的模式下不能正常触发。

怎样解决:

  • 尽量避免将NSTimer放入容易阻塞的主线程中。
  • 避免将耗时的操作放到NSTimer的线程中。
  • 避免在NSTimer中进行耗时的操作,如果不能避免,就将操作转移到其他线程。

11. 什么是常驻线程,线程保活

  • 常驻线程:在应用程序在运行期间始终存在的线程,用于执行持续运行的任务,这些线程通常不会因为任务执行完成而终止,而是持续运行以支持应用程序的正常运行。
  • 线程保活:一种确保线程持续运行的机制,即使在没有任务的时候,也能保证线程存活。

多线程

1. 队多线程的理解

好处
  • 使用多线程可以把占据时间长的任务放到后台去处理。
  • 程序运行速度可能加快。
  • 在等待任务(用户输入,网络收发数据)的实现上,多线程比较有用。
坏处
  • 如果有大量线程,因为操作系统需要在他们之间切换。
  • 更多的线程需要更多的内存空间。
  • 线程的中止需要考虑对程序运行的影响。
  • 需要防止程序死锁的情况。

2. iOS多线程的方式有哪几种

实现多线程的方法:

请添加图片描述
更倾向于GCD和NSOperation,封装更高级,使用起来更方便。

3. 有用过GCD吗

  1. 在其他线程请求完整数据,在主线程更新UI
  //让处理在主线程中执行
	dispatch_async(dispatch_get main_queue(), ^{
		/*
		 *只在主线程可以执行的处理
		 *例如用户界面更新
		 */
	});
 
  1. Manager封装网络请求,可以使用GCD实现
 - (void)once {        //GCD的一次性代码(只执行一次)
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        // 只执行1次的代码(这里面默认是线程安全的)
    });
}

  1. GCD定时器
- (void)after {
    NSLog(@"run -- 0");
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        // 2秒后异步执行这里的代码...
       NSLog(@"run -- 2");
    });
}
 
  1. 信号量加锁保证线程安全
     dispatch_semaphore_t semalook = dispatch_semaphore_create(1);
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_semaphore_wait(semalook, DISPATCH_TIME_FOREVER);
        NSLog(@"1开始");
        sleep(2);
        NSLog(@"1结束");
        dispatch_semaphore_signal(semalook);
    });
    
    dispatch_async(dispatch_get_global_queue(0, 0), ^{
        dispatch_semaphore_wait(semalook, DISPATCH_TIME_FOREVER);
        NSLog(@"2开始");
        sleep(2);
        NSLog(@"2结束");
        dispatch_semaphore_signal(semalook);
    });


4. GCD的队列类型

可以使用dispatch_queue_create来创建对象,需要传入两个参数,第一个参数表示队列的唯一标识符,用于DEBUG,可为空;第二个参数用来识别是串行队列还是并发队列。DISPATCH_QUEUE_SERIAL表示串行队列,DISPATCH_QUEUE_CONCURRENT表示并发队列。

 // 串行队列的创建方法
dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_SERIAL);
// 并发队列的创建方法
dispatch_queue_t queue= dispatch_queue_create("test.queue", DISPATCH_QUEUE_CONCURRENT);

5. NSOperationQueue和GCD的区别以及优势

区别:
  1. GCD执行的效率更高,队列中执行的是由block构成的任务,写起来比较方便。
  2. GCD只支持FIFO的队列,但是NSOperationQueue可以设置最大并发数,设置优先级,添加依赖,调整顺序。
  3. NSOperationQueue可以在队列中设置依赖关系,但是GCD只能通过设置串行队列,或者在队列内添加barrier(dispatch_barrier_async)任务,才能控制执行顺序,较为复杂。
  4. NSOperationQueue因为面向对象,所以支持KVO,可以监测operation是否正在执行(isExecuted)、是否结束(isFinished)、是否取消(isCanceld

6. 线程安全的处理手段

  • 互斥锁(Mutex):使用互斥锁可以确保同时时间只有一个线程访问共享资源,在Objective-C中,可以使用@synchronized关键字来创建互斥锁。
 @synchronized (self) {
    // 访问共享资源的代码
}

  • 自旋锁(Spin Lock):自旋锁是一种忙等待锁,不断尝试获取锁,直到成功为止。在Objective-C中,可以使用os_unfair_lock来创建自旋锁。
 os_unfair_lock_t lock = &(OS_UNFAIR_LOCK_INIT);
os_unfair_lock_lock(lock);
// 访问共享资源的代码
os_unfair_lock_unlock(lock);

  • 信号量(Semaphore):信量是一种数器,用于控制同时访问某个资源的线程数量,在Objective-C中可以使用dispatch_semaphore来创建信号量。
 dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// 访问共享资源的代码
dispatch_semaphore_signal(semaphore);

  • 原子操作(Atomic Operations):原子操作是一种特的操作,可以确保对共享资源的读写操作是原子的,即不会被其他线程中断。在Objective-C中,可以使用atomic键字来声明属性原子类型。
 @property (atomic, strong) NSObject *sharedObject;

  • 串行队列(Serial Queue):使用串行队列可以确保任务按顺序执行,从而避多个线程同时访问共享资源。可以使用GCD(Grand Central Dispatch)来创建串行队列。
 dispatch_queue_t serialQueue = dispatch_queue_create("com.example.serialQueue DISPATCH_QUEUE_SERIAL);
dispatch_async(serialQueue, ^{
    // 访问共享资源的代码
});

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

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

相关文章

【pytorch学习】transforms的使用

1 ToTensor() 作用&#xff1a;将 PIL Image 类型或者 numpy.ndarray 类型转为 tensor 类型 实例&#xff1a; from torchvision import transforms from PIL import Imageimg_path "data/train/bees/17209602_fe5a5a746f.jpg" img Image.open(img_path)print(i…

[数据结构]-快速排序

学习快排的基础 不想自己推导时间复杂度或者了解随机化的合理性,可以忽视下面这一条. 推导时间复杂度的方法:主定理随机化算法—数学基础:概率统计 QuickSort 快速排序: 1962年,Tony Hoare发明了这种如此高效实用的强大排序算法 分治法的体现:Divide and Conquer原地排序,…

数据结构+二叉遍历算法的应用

一、问题描述 编写一个程序&#xff0c;先用二叉树表示一个简单算术表达式&#xff0c;树的每一个 结点包括一个运算符或运算数。在简单算术表达式中只包含、-、 *、/和一位正整数且格式正确(不包含括号)&#xff0c;并且要按照先乘除后 加减的原则构造二叉树。如图 7.35 所示…

QT5生成独立运行的exe文件

目录 1 生成独立运行的exe文件1.1 设置工程Release版本可执行文件存储路径1.2 将工程编译成Release版本 2 使用QT5自带的windeployqt拷贝软件运行依赖项3 将程序打包成一个独立的可执行软件exe4 解决QT5 This application failed to start because no Qt platform plugin could…

批量快递中问题件筛选技巧大揭秘

批量快递中问题件筛选技巧大揭秘&#xff1a;固乔快递查询助手的强大功能 在电商行业日益繁荣的今天&#xff0c;快递服务成为了连接商家与消费者的关键纽带。然而&#xff0c;随着订单量的激增&#xff0c;如何高效处理并筛选出快递中的问题件&#xff0c;成为了许多商家面临…

shuishusihui

互斥量 使用互斥量可以用于保护某些临界资源&#xff0c;同一时间只能有一个任务来使用它。 使用互斥量会引入其他问题&#xff0c;比如说优先级反转&#xff0c;于是提出了优先级继承等方法解决问题 任务通知 任务通知就是通知任务&#xff0c;前边都是多对多的关系&#xff0…

算法解析——双指针算法(3)数据匹配

欢迎来到博主的专栏——算法解析 博主ID&#xff1a;代码小豪 文章目录 LCR179、查找总价格为目标值的两个商品leetcode11——盛水最多的容器leetcode611——有效三角形的个数 我们前面已经盘点了两种双指针算法的使用场景&#xff0c;现在来看看最常见的一种。 通常&#xff0…

社交电商系统开发功能定制

社交电商系统开发功能定制是一项综合性的服务&#xff0c;它涉及到需求分析、界面设计、功能开发、系统测试以及上线后的持续维护。以下是社交电商系统开发中应考虑的关键功能点&#xff1a; 需求分析和规划&#xff1a;开发前&#xff0c;企业需要明确业务需求&#xff0c;包…

【数据分析:一篇文章带你掌握Pandas高级可视化技巧】

前言&#xff1a; &#x1f49e;&#x1f49e;大家好&#xff0c;我是书生♡&#xff0c;本阶段和大家一起分享和探索数据分析的数据可视化&#xff0c;本篇文章主要讲述了&#xff1a;掌握Pandas高级可视化技巧等等。欢迎大家一起探索讨论&#xff01;&#xff01;&#xff01…

docker的swarm技术

docker中swarm技术 docker swarm技术是docker社区提供的docker的集群管理调度工具&#xff0c;通过api来管理多个主机上的docker&#xff0c;通过overlay网络来实现不同主机之间容器的通信与访问。实现容器的调度&#xff0c;资源的分配&#xff0c;以及副本。 docker swarm中…

愛ㄉ粗麵體字體欣赏

愛ㄉ粗麵體字體字体欣赏&#xff0c;英文名AddaNoodle 下载到字体档后&#xff0c;首先打开字体文件预览看看&#xff0c;超可愛的&#xff5e; 最近流行的可愛字體&#xff0c;VIVISTICKER-愛ㄉ粗麵體 QQ 軟軟的筆觸不只適合有溫度的限動 放在貼文或介紹文字都超級適合 還找不…

汇编语言指令 jmp: jmp word ptr、jmp dword ptr、jmp 寄存器、jmp 段地址:偏移地址

1. 转移地址在内存中的jmp指令有2种形式 1.1 jmp word ptr 内存单元地址 jmp word ptr 内存单元地址是段内转移指令&#xff0c;也就是说该指令只修改IP值&#xff0c;其功能是控制CPU下一条执行的指令是一个字&#xff08;2个字节&#xff09;内存中存放的偏移地址所指向的指…

【Python】函数入门(下)

3&#xff09;&#xff09;* ** ​​​​​​注意&#xff1a;也遵循位置传参在前面&#xff0c;按关键字传参在后面。 代码示例&#xff1a; def func(*args,**kwargs):print(args,kwargs) 该函数中的参数会自动根据传参的方式不同&#xff08;即&#xff1a;按位置…

家电行业实施数字工厂管理系统前要做好哪些准备

家电企业在实施数字工厂管理系统前&#xff0c;需要做好以下准备&#xff1a; 一、明确目标与需求 数字化转型目标&#xff1a;明确数字化转型的具体目标&#xff0c;如提高生产效率、降低生产成本、优化库存管理、提升产品质量等。这些目标将指导整个数字工厂管理系统的选择…

STM32学习笔记09-SPI通信

目录 SPI通信简介 硬件电路 移位示意图 SPI基本时序单元 SPI时序 W25Q64简介 硬件电路 W25Q64框图 Flash操作注意事项 SPI外设简介 SPI框图 SPI基本结构 主模式全双工连续传输 非连续传输 软件/硬件波形对比 SPI应用 软件SPI读写W25Q64 硬件SPI读写W25Q64 SP…

在复制 PowerPoint (PPT) 文件时,其中嵌入或者链接的 Excel 文件能够自动创建一个新的实例,而不是继续引用原始的 Excel 文件。

问题&#xff1a; 在复制 PowerPoint (PPT) 文件时&#xff0c;其中嵌入或者链接的 Excel 文件能够自动创建一个新的实例&#xff0c;而不是继续引用原始的 Excel 文件。 解答&#xff1a; 导入已有的excel实测是不行的

为什么程序员应该学习多种语言?

前言 有一句老话适用于所有软件开发人员&#xff1a;知道得越多&#xff0c;成长得越多。程序员学习多种编程语言后、‌可以加速学习新技术、‌拓展认知和视野。‌ 对于程序员来说&#xff0c;‌精通一门编程语言意味着对该语言有深入的理解和熟练的运用&#xff0c;‌这为程…

LLMCompiler执行数学计算的案例

LLMCompiler执行数学计算的案例 LLMCompiler执行数学计算的案例案例代码LLMCompiler的LangGrap结构可视化Tasks DAG可视化完整运行日志 LLMCompiler执行数学计算的案例 这是一个使用LLMCompiler执行数学运算的完整案例&#xff0c;通过设置’ print_dag 参数&#xff0c;可以完…

vme背板 介绍

VME背板是基于VME总线规范的背板,它是VME系统中的重要组成部分,主要负责模块之间的连接和数据传输。VMEbus(Versa Module Eurocard bus)是一种广泛应用于工业控制、军事、航空航天以及电信领域的模块化计算机总线标准。VME背板是VME系统的核心组件之一,它不仅提供了物理支…

思路超清晰的 LVS-NAT 模式实验部署

目录 一、实验原理 1、实验基础配置图 2、实验原理 二、实验环境准备 1、准备四台红帽9的主机 2、四台主机的基础配置 &#xff08;1&#xff09;client 1&#xff09;配置主机名&#xff1a;client 2&#xff09;配置ip:172.25.254.200 &#xff08;2&#xff09;lv…