Runloop原理(二)

Runloop原理(一)

之前的 Runloop原理(一) 中測(cè)試是在主線程進(jìn)行的,接下來(lái)在子線程中進(jìn)行

以下涉及的內(nèi)容均是針對(duì)子線程的

Starting the Run Loop

只有在子線程中啟動(dòng)runloop 才是必要的

runloop必須至少有一個(gè)inpurt source 或者 timer,如果一個(gè)也沒(méi)有,則runloop 馬上退出

啟動(dòng)runloop有幾種方式

  • Unconditionally

    無(wú)條件進(jìn)入runloop是最簡(jiǎn)單的選擇,但也是最不可取的;

    無(wú)條件地運(yùn)行runloop會(huì)使線程進(jìn)入永久循環(huán),這使得你對(duì)runloop本身幾乎沒(méi)有控制權(quán)

    你可以添加和刪除input sources和timer,但唯一能停止runloop的方法是終止它,也沒(méi)有辦法在custom mode中運(yùn)行runloop

  • With a set time limit

    設(shè)定限制時(shí)間

    如果設(shè)定超時(shí),runloop將一直運(yùn)行直到事件到達(dá)或者分配的時(shí)間過(guò)期為止

  • In a particular mode

    在特定mode下

線程主入口框架版本

image.png

子線程中 沒(méi)有啟動(dòng)runloop,timer是沒(méi)辦法調(diào)度執(zhí)行的,而且子線程一啟動(dòng),馬上就銷毀了

image.png

無(wú)條件啟動(dòng)runloop,timer調(diào)度執(zhí)行, 而且直接run runloop,后面的代碼執(zhí)行阻塞

此時(shí) 主動(dòng)讓線程exit, timer也停止,說(shuō)明timer調(diào)度是依托于runloop的

runloop添加非基于port的input source

image.png

對(duì)于非基于port的input source,runloop休眠,監(jiān)視source的signal事件,如果沒(méi)有其他線程對(duì)source的signal,runloop將超時(shí) 退出

也就是

image.png

runloop通過(guò)Core Foundation添加timer

image.png

runloop啟動(dòng)之后有超時(shí),圖中設(shè)置了10秒超時(shí)

雖然timer每5秒觸發(fā)一次,但timer卻是基于runloop調(diào)度的

過(guò)10秒之后 runloop超時(shí) 退出,因?yàn)椴捎昧藈hile,所以runloop退出之后又重新啟動(dòng)

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

為了更直觀的了解timer究竟是如何調(diào)度的,這里再總結(jié)一次

  • 首先開(kāi)啟一個(gè)子線程
image.png
  • runloop 注冊(cè)observer
image.png
  • observer通知回調(diào)
image.png
  • runloop 添加timer
image.png
  • timer 任務(wù)
image.png
  • 添加source (非基于port)
image.png
  • source注冊(cè)回調(diào)函數(shù)
image.png
  • 控制臺(tái)結(jié)果打印 -------
image.png

關(guān)于timer的流程打印總結(jié)說(shuō)明

  • 首先進(jìn)入runloop (配置的啟動(dòng)方式為非阻塞的,超時(shí)會(huì)退出)

  • 發(fā)現(xiàn)有timer,通知observer即將處理timer任務(wù)調(diào)度

    但是timer的任務(wù)調(diào)度是按照計(jì)劃設(shè)置的時(shí)間表來(lái)執(zhí)行的,進(jìn)入runloop第一件事是先檢查是否配置了timer計(jì)劃

    有計(jì)劃不代表runloop馬上要調(diào)度timer任務(wù)去執(zhí)行,而是看當(dāng)前的時(shí)間是否到了計(jì)劃的執(zhí)行時(shí)間,如果時(shí)間到了,就調(diào)度task執(zhí)行,如果沒(méi)到,心里有數(shù),繼續(xù)下一項(xiàng)議題 source

  • 發(fā)現(xiàn)有source,通知observer即將處理source

    source的執(zhí)行需要有signal,沒(méi)有signal什么也不做

    跟timer類似,就是runloop調(diào)度計(jì)劃表里有source,但是調(diào)度執(zhí)行需要一個(gè)契機(jī), 這個(gè)契機(jī)就是signal

  • 接下來(lái)通知observer即將休眠

  • 當(dāng)前時(shí)間如果符合 timer計(jì)劃表里的時(shí)間點(diǎn),喚醒runloop, runloop 通知observer喚醒

    喚醒發(fā)生在timer調(diào)度任務(wù)執(zhí)行之前

  • 執(zhí)行timer任務(wù)

  • 如果此時(shí)runloop 10秒超時(shí)未過(guò)期,將重新啟動(dòng)循環(huán), 即將進(jìn)入timer開(kāi)始

    • 繼續(xù)一輪循環(huán) 即將進(jìn)入timer -> 即將處理source -> 休眠 -> timer喚醒 -> 馬上退出
  • 如果此時(shí)runloop 10秒超時(shí)過(guò)期,runloop退出

source的執(zhí)行是怎么樣的

signal + wakeup

image.png

touch 一下

image.png

touch之后,runloop喚醒,此時(shí)你會(huì)發(fā)現(xiàn),即將進(jìn)入source之后 --> 執(zhí)行source --> 退出 --> 進(jìn)入runloop

喚醒runloop,循環(huán)輪詢一次,source執(zhí)行之后,會(huì)馬上退出。之所以這樣,是因?yàn)閠ouch顯式喚醒runloop會(huì)重新啟動(dòng)runloop

退出runloop

有兩種方式退出tunloop

  • runloop設(shè)置超時(shí)

  • 告訴runloop stop --- CFRunLoopStop

雖然移除 input sources 和 timers可以引起runloop退出,但這是不可靠的. 一些系統(tǒng)例程將input sources添加到runloop中以處理所需的事件, 你的代碼可能不知道這些input sources,所以無(wú)法刪除它們,這將阻止runloop退出

線程安全和runloop對(duì)象

線程安全取決于你使用哪種api操作runloop

  • Core Foundation里的方法通常是線程安全的,可以在任何線程里調(diào)用

  • Cocoa NSRunLoop類不像Core Foundation對(duì)應(yīng)類那樣天生安全

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

    在線程里往runloop里添加input source 和timer,但是runloop屬于其他線程, 就會(huì)崩潰

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容