Runloop原理(二)

作者: erlich | 来源:发表于2022-06-22 17:31 被阅读0次

    Runloop原理(一)

    之前的 Runloop原理(一) 中测试是在主线程进行的,接下来在子线程中进行

    以下涉及的内容均是针对子线程的

    Starting the Run Loop

    只有在子线程中启动runloop 才是必要的

    runloop必须至少有一个inpurt source 或者 timer,如果一个也没有,则runloop 马上退出

    启动runloop有几种方式

    • Unconditionally

      无条件进入runloop是最简单的选择,但也是最不可取的;

      无条件地运行runloop会使线程进入永久循环,这使得你对runloop本身几乎没有控制权

      你可以添加和删除input sources和timer,但唯一能停止runloop的方法是终止它,也没有办法在custom mode中运行runloop

    • With a set time limit

      设定限制时间

      如果设定超时,runloop将一直运行直到事件到达或者分配的时间过期为止

    • In a particular mode

      在特定mode下

    线程主入口框架版本

    image.png

    子线程中 没有启动runloop,timer是没办法调度执行的,而且子线程一启动,马上就销毁了

    image.png

    无条件启动runloop,timer调度执行, 而且直接run runloop,后面的代码执行阻塞

    此时 主动让线程exit, timer也停止,说明timer调度是依托于runloop的

    runloop添加非基于port的input source

    image.png

    对于非基于port的input source,runloop休眠,监视source的signal事件,如果没有其他线程对source的signal,runloop将超时 退出

    也就是

    image.png

    runloop通过Core Foundation添加timer

    image.png

    runloop启动之后有超时,图中设置了10秒超时

    虽然timer每5秒触发一次,但timer却是基于runloop调度的

    过10秒之后 runloop超时 退出,因为采用了while,所以runloop退出之后又重新启动

    添加timer - 直观演示runloop流程序列

    为了更直观的了解timer究竟是如何调度的,这里再总结一次

    • 首先开启一个子线程
    image.png
    • runloop 注册observer
    image.png
    • observer通知回调
    image.png
    • runloop 添加timer
    image.png
    • timer 任务
    image.png
    • 添加source (非基于port)
    image.png
    • source注册回调函数
    image.png
    • 控制台结果打印 -------
    image.png

    关于timer的流程打印总结说明

    • 首先进入runloop (配置的启动方式为非阻塞的,超时会退出)

    • 发现有timer,通知observer即将处理timer任务调度

      但是timer的任务调度是按照计划设置的时间表来执行的,进入runloop第一件事是先检查是否配置了timer计划

      有计划不代表runloop马上要调度timer任务去执行,而是看当前的时间是否到了计划的执行时间,如果时间到了,就调度task执行,如果没到,心里有数,继续下一项议题 source

    • 发现有source,通知observer即将处理source

      source的执行需要有signal,没有signal什么也不做

      跟timer类似,就是runloop调度计划表里有source,但是调度执行需要一个契机, 这个契机就是signal

    • 接下来通知observer即将休眠

    • 当前时间如果符合 timer计划表里的时间点,唤醒runloop, runloop 通知observer唤醒

      唤醒发生在timer调度任务执行之前

    • 执行timer任务

    • 如果此时runloop 10秒超时未过期,将重新启动循环, 即将进入timer开始

      • 继续一轮循环 即将进入timer -> 即将处理source -> 休眠 -> timer唤醒 -> 马上退出
    • 如果此时runloop 10秒超时过期,runloop退出

    source的执行是怎么样的

    signal + wakeup

    image.png

    touch 一下

    image.png

    touch之后,runloop唤醒,此时你会发现,即将进入source之后 --> 执行source --> 退出 --> 进入runloop

    唤醒runloop,循环轮询一次,source执行之后,会马上退出。之所以这样,是因为touch显式唤醒runloop会重新启动runloop

    退出runloop

    有两种方式退出tunloop

    • runloop设置超时

    • 告诉runloop stop --- CFRunLoopStop

    虽然移除 input sources 和 timers可以引起runloop退出,但这是不可靠的. 一些系统例程将input sources添加到runloop中以处理所需的事件, 你的代码可能不知道这些input sources,所以无法删除它们,这将阻止runloop退出

    线程安全和runloop对象

    线程安全取决于你使用哪种api操作runloop

    • Core Foundation里的方法通常是线程安全的,可以在任何线程里调用

    • Cocoa NSRunLoop类不像Core Foundation对应类那样天生安全

      如果你使用NSRunLoop修改runloop,你只能在此runloop的线程里操作

      在线程里往runloop里添加input source 和timer,但是runloop属于其他线程, 就会崩溃

    相关文章

      网友评论

        本文标题:Runloop原理(二)

        本文链接:https://www.haomeiwen.com/subject/ewpuvrtx.html