1.OCå
å管ç-runloop
2.Chromium setTimeout/clearTimeout 源码分析
OCå å管ç-runloop
RunLoop æ¯éè¿å é¨ç»´æ¤ç äºä»¶å¾ªç¯( Event Loop )æ¥å¯¹ äºä»¶/æ¶æ¯è¿è¡ç®¡ççä¸ä¸ªå¯¹è±¡ãrunloop çå®æ¹ææ¡£å¨ thread ç¯ç« Run Loops ï¼ä¹å°±ä»ä¾§é¢è¯´æäº runloop æ¯ä¸çº¿ç¨æ¯æ¯ç¸å ³çã
å®æ¹æå¦ä¸ä¸å¼ å¾ï¼
线ç¨çè¾å ¥æº:
线ç¨é对è¾å ¥æºçå¤çæºå¶ï¼
æ以ä¸æ¡ä¾ï¼
timer ä¸ performSelector 对åºçåè°é½æ¯ __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ ï¼
block å¯¹åº __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ ï¼
主线ç¨å¯¹åº __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ :
ç³»ç»è§¦æ¸äºä»¶å¯¹åº __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ ï¼
éç¥äºä»¶å¯¹åº __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ ï¼
å°ç»ï¼
æ»å¨é¡µé¢è¾åºï¼
页é¢æ»å¨è¿ç¨ä¸å¤äº UITrackingRunLoopMode ï¼éæ¢ç¶æå¤äº kCFRunLoopDefaultMode ã
è¾åºï¼
è¾åºï¼
æ¢ç¶ runloop æ¯ä¸ä¸ªäºä»¶å¾ªç¯ï¼é£ä¹å®ä¸æ®éç循ç¯æä»ä¹åºå«å¢ï¼
æ®é循ç¯ï¼
runloop 循ç¯ï¼
é£ä¹å¯ä»¥å¾å°ä»¥ä¸ç»è®ºï¼
é£ä¹ runloop æ¯æä¹åå°çå¢ï¼
é常æ们ä¼éè¿ NSRunLoop å»è·åå½åç runloop ï¼
å®ä¹å¦ä¸ï¼
ç» currentRunLoop ä¸ç¬¦å·æç¹ï¼
éè¿ä¹åçåæå·²ç»å®ä½å°äº runloop æ¯å¨ CoreFoundation ä¸ç CoreFoundationæºç ãæ£å¥½ CoreFoundation å¼æºäº CFRunLoop ï¼
é£ä¹æ ¸å¿é»è¾å°±å¨ CFRunLoopRunSpecific ä¸ãè¿æä¸ä¸ªçé®æ¯ runloop å¯ä»¥ä¼ç ï¼é£ä¹å®æ¯å¦ä½å®ç°çå¢ï¼
è¦äºè§£ runloop çå®ç°åçï¼é¦å è¦æ¸ æ¥å®çæ°æ®ç»æã
CFRunLoopRunSpecific ç第ä¸ä¸ªåæ°æ¯ CFRunLoopGetCurrent() ï¼
_CFRunLoopGet0
CFRunLoopRef çå®ä¹å¦ä¸ï¼
å®é ä¸åºå±å®æ¯ __CFRunLoop ç±»åï¼
å¯¹äº timer èè¨:
æ¾ç¶å®æ¯è¦ä¾èµ mode çã
CFRunLoopMode
èä¸ä¸ª mode ä¸å对åºå¤ä¸ª items(source0ãsource1ãtimersãobservers) ï¼æ以就æå¦ä¸å ³ç³»ï¼
æ¢ç¶æå¤ç§ mode ï¼é£ä¹é½æåªäºå¢ï¼
æºç ä¸æå¦ä¸å®ä¹ï¼
å®ä»¬å¯¹åº Foundation ä¸çï¼
æ们é½æ¸ æ¥å¨é¡µé¢æ»å¨çæ¶åæä¸ä¸ª UITrackingRunLoopMode ï¼
é¤äºä»¥ä¸ 3 ç§ mode è¿æ两个ç§æ mode ï¼
å½ RunLoop è¿è¡å¨ Mode1 ä¸æ¶ï¼æ¯æ æ³æ¥åå¤ç Mode2 æ Mode3 ä¸ç SourceãTimerãObserver äºä»¶çã
以 timer 为ä¾ï¼å° timer å å ¥å° runloop ä¸ï¼
åºå±è°ç¨äº CFRunLoopAddTimer ï¼
æ ¹æ®è¦å å ¥ç mode åºåæ¯ common mode åé common mode å° timer å å ¥ mode ä¸ãè¿ä¸ªæ¶ååªæ¯å° timer å å ¥äº mode ä¸ï¼è¦æ§è¡è¯å®è¦è°ç¨ CFRunLoopRun ï¼æç»è¦è°ç¨ CFRunLoopRunSpecific ã
å¨ __CFRunLoopRun ä¸è°ç¨äº __CFRunLoopDoTimers ï¼
æ¾å° mode ä¸çææ timer ç¶åè°ç¨ __CFRunLoopDoTimer ã
CFRunLoopAddTimer -> CFRunLoopRunSpecific -> __CFRunLoopRun -> __CFRunLoopDoTimers -> __CFRunLoopDoTimer -> __CFRUNLOOP_IS_CALLING_OUT_TO_A_TIMER_CALLBACK_FUNCTION__ ã
ä¸ timer ç¸å source ä¼è°ç¨ CFRunLoopAddSource ï¼
CFRunLoopAddSource -> CFRunLoopRunSpecific -> __CFRunLoopRun -> __CFRunLoopDoSources0/__CFRunLoopDoSources1 -> __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ /__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE1_PERFORM_FUNCTION__
åç observer ä¼è°ç¨ CFRunLoopAddObserver ã
Chromium setTimeout/clearTimeout 源码分析
Chromium版本.0..3中setTimeout函数的工作流程涉及大量源码,包括线程、消息循环、任务队列和操作系统定时器函数。源码最高几级本文仅分析setTimeout的关键步骤。
setTimeout函数通过创建包含回调函数和延时时间的action对象,调用DOMTimer::Install进行处理。DOMTimer::Install通过DOMTimerCoordinator::InstallNewTimeout向定时器哈希表timers_插入一个定时器对象,生成唯一timeout_id。
timeout_id由NextID生成,每次调用setTimeout返回递增的TSlib.lua源码值,用于唯一标识每个定时器任务。timers_是一个哈希表,存放定时器对象,与任务一一对应。
创建定时器对象时,ugui源码研究意义通过定时器的延时时间获取任务类型,并将回调函数与任务类型关联,最终通过web_task_runner_获取相应的任务运行器,并在TimerBase::SetNextFireTime调用web_task_runner_->PostDelayedTask提交延迟任务。
PostDelayedTask将延迟任务插入到延迟任务队列中,运行周期指标源码并更新当前线程的唤醒时间。延迟任务队列是优先队列,用于管理按延时时间排序的任务。
通过GetNextScheduledWakeUpImpl获取优先队列的队头任务,创建唤醒任务用于在线程唤醒时执行延迟任务。河北网校系统源码唤醒任务只包含延时时间,不包含回调函数。
UpdateDelayedWakeUpImpl根据新创建的唤醒任务更新唤醒任务队列。如果延迟任务队列中的任务延时时间较短,新任务可能无法立即进入唤醒任务队列。
调用操作系统定时器函数,如在Mac下调用CFRunLoopTimerSetNextFireDate,在Windows下调用SetTimer,在Android下调用timerfd_settime,在指定延时后唤醒线程。
线程睡眠后,唤醒线程执行已到期的延迟任务,将到期任务从延迟任务队列移出并加入工作队列。ThreadControllerWithMessagePumpImpl::DoWorkImpl找到并执行工作队列中的任务。
面试题:setTimeout延迟时间不准确的原因可能有:硬件层面的时间不准确、操作系统不保证定时器函数的精确性、CPU处理大量定时任务时可能出现部分任务延迟执行。
clearTimeout与clearInterval功能相同,DOMTimer::RemoveByID从timers_哈希表中移除指定timeout_id对应的定时器对象,将回调函数置空,视为任务取消。