Runloop源码解析:运行逻辑

Runloop应用:

  • Timer失效问题;
  • 线程保活;

Runloop的运行逻辑:

入口函数

SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled)
  1. 通知Observers:进入Loop;
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
  1. 通知Observers:即将处理Timers;
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
  1. 通知Observers:即将处理Sources;
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
  1. 处理Blocks;
__CFRunLoopDoBlocks(rl, rlm);
  1. 处理Source0(可能会再次处理Blocks);
Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
        if (sourceHandledThisLoop) {
            __CFRunLoopDoBlocks(rl, rlm);
    }
  1. 如果存在Source1,就跳转到第8步;
if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL)) {
                goto handle_msg;
            }
  1. 通知Observers:开始休眠(等待消息唤醒);
//通知Observers:即将休眠
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
__CFRunLoopSetSleeping(rl);

//等待别的消息来唤醒当前线程
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
            
  1. 通知Observers:结束休眠(被某个消息唤醒):
//通知Observers:结束休眠
 __CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);

  1. 处理Timer;
  2. 处理GCD Async To Main Queue;
  3. 处理Source1;
if(被timer唤醒) {
//处理Timers
__CFRunLoopDoTimers(rl, rlm, mach_absolute_time());
} else if (被GCD唤醒) {
//处理CGD
__CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__(msg);

} else { //被Source1唤醒
//处理Source1
 __CFRunLoopDoSource1(rl, rlm, rls, msg, msg->msgh_size, &reply) || sourceHandledThisLoop;
}

  1. 处理Blocks;
__CFRunLoopDoBlocks(rl, rlm);

  1. 根据前面的执行结果,决定如何操作:
    1. 回到第02步;
    2. 或 退出Loop;
 if (sourceHandledThisLoop && stopAfterHandle) {
         retVal = kCFRunLoopRunHandledSource;
         } else if (timeout_context->termTSR <  mach_absolute_time()) {
             retVal = kCFRunLoopRunTimedOut;
     } else if (__CFRunLoopIsStopped(rl)) {
             __CFRunLoopUnsetStopped(rl);
         retVal = kCFRunLoopRunStopped;
     } else if (rlm->_stopped) {
         rlm->_stopped = false;
         retVal = kCFRunLoopRunStopped;
     } else if (__CFRunLoopModeIsEmpty(rl, rlm, previousMode)) {
         retVal = kCFRunLoopRunFinished;
     }
 } while (0 == retVal);
  1. 通知Observers:退出Loop.
 __CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);

扩展:Runloop休眠实现的原理:

  • runloop休眠函数:
//等待别的消息来唤醒当前线程
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
  • 原理:通过函数mach_msg()切换到内核态,控制线程休眠。

线程阻塞有两种方式:

  1. 代码阻塞,但是当前线程并没有休息;
  • 如下,死循环:
while(1);
  1. 真的让当前线程去“休息”。
  • 内核层面API:mach_msg()
    1. 没有消息就让线程休眠;
    2. 有消息就唤醒。

你可能感兴趣的:(Runloop源码解析:运行逻辑)