Runloop应用:
Runloop的运行逻辑:
入口函数
SInt32 CFRunLoopRunSpecific(CFRunLoopRef rl, CFStringRef modeName, CFTimeInterval seconds, Boolean returnAfterSourceHandled)
- 通知Observers:进入Loop;
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopEntry);
- 通知Observers:即将处理Timers;
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeTimers);
- 通知Observers:即将处理Sources;
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeSources);
- 处理Blocks;
__CFRunLoopDoBlocks(rl, rlm);
- 处理Source0(可能会再次处理Blocks);
Boolean sourceHandledThisLoop = __CFRunLoopDoSources0(rl, rlm, stopAfterHandle);
if (sourceHandledThisLoop) {
__CFRunLoopDoBlocks(rl, rlm);
}
- 如果存在Source1,就跳转到第8步;
if (__CFRunLoopServiceMachPort(dispatchPort, &msg, sizeof(msg_buffer), &livePort, 0, &voucherState, NULL)) {
goto handle_msg;
}
- 通知Observers:开始休眠(等待消息唤醒);
//通知Observers:即将休眠
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopBeforeWaiting);
__CFRunLoopSetSleeping(rl);
//等待别的消息来唤醒当前线程
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
- 通知Observers:结束休眠(被某个消息唤醒):
//通知Observers:结束休眠
__CFRunLoopDoObservers(rl, rlm, kCFRunLoopAfterWaiting);
- 处理Timer;
- 处理GCD Async To Main Queue;
- 处理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;
}
- 处理Blocks;
__CFRunLoopDoBlocks(rl, rlm);
- 根据前面的执行结果,决定如何操作:
- 回到第02步;
- 或 退出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);
- 通知Observers:退出Loop.
__CFRunLoopDoObservers(rl, currentMode, kCFRunLoopExit);
扩展:Runloop休眠实现的原理:
- runloop休眠函数:
//等待别的消息来唤醒当前线程
__CFRunLoopServiceMachPort(waitSet, &msg, sizeof(msg_buffer), &livePort, poll ? 0 : TIMEOUT_INFINITY, &voucherState, &voucherCopy);
- 原理:通过函数
mach_msg()
切换到内核态,控制线程休眠。
线程阻塞有两种方式:
- 代码阻塞,但是当前线程并没有休息;
- 如下,死循环:
while(1);
- 真的让当前线程去“休息”。
- 内核层面API:
mach_msg()
- 没有消息就让线程休眠;
- 有消息就唤醒。