资源预览内容
第1页 / 共9页
第2页 / 共9页
第3页 / 共9页
第4页 / 共9页
第5页 / 共9页
第6页 / 共9页
第7页 / 共9页
第8页 / 共9页
第9页 / 共9页
亲,该文档总共9页全部预览完了,如果喜欢就下载吧!
资源描述
RunLoop 总结:RunLoop 基础知识什么是 RunLoop?顾名思义,它就是一个运行循环。一个 RunLoop 就是一个用于处理既定工作和接收到的外来事件的事件处理循环。RunLoop 的存在目的就是当线程中有任务时,保证线程忙着干活;当线程中没有任务时,让线程睡眠,以节省资料(想想看,你是在房间里一直转圈抗饿还是躺在床上睡觉更抗饿?) 。 理解了 EventLoop 就 能很好的理解 RunLoop 了。 简单的用伪代码来表示就是这样的:function loop() initialize();while (message != quit) var message = get_next_message();process_message(message); 关于 RunLoop,苹果的 Cocoa 和 CoreFoundation 框架都分别提供了 NSRunLoop 和 CFRunLoopRef 供开发者调用和执行操作。 CFRunLoopRef 只是一个结构体,而 NSRunLoop 是一个 NSObject 对象,必然是苹果将 CFRunLoopRef 进行了封装。 需要注意的是 NSRunLoop 并不是线程安全的,而 CFRunLoopRef 是线程安全的。 官方文档原文是:Thread safety varies depending on which API you are using to manipulate your run loop. The functions in Core Foundation are generally thread-safe and can be called from any thread. If you are performing operations that alter the configuration of the run loop, however, it is still good practice to do so from the thread that owns the run loop whenever possible.The Cocoa NSRunLoop class is not as inherently thread safe as its Core Foundation counterpart. If you are using the NSRunLoop class to modify your run loop, you should do so only from the same thread that owns that run loop. Adding an input source or timer to a run loop belonging to a different thread could cause your code to crash or behave in an unexpected way.接下来,看一下 CFRunLoopRef 里都保存了哪些数据?可以从 CF 框架源码 的 CFRunLoop.h 和 CFRunLoop.c,看看 苹果对 CFRunLoopRef 的定义。 CFRunLoopRef 是 结构体_CFRunLoop *的重命名,由 typedef struct _CFRunLoop * CFRunLoopRef; 可知; _CFRunLoop 的定义:struct _CFRunLoop CFRuntimeBase _base;pthread_mutex_t _lock; /* locked for accessing mode list,每次读取 mode list 要加锁 */_CFPort _wakeUpPort; / used for CFRunLoopWakeUp Boolean _unused;volatile _per_run_data *_perRunData; / reset for runs of the run looppthread_t _pthread; /与该 runLoop 关联的线程uint32_t _winthread;CFMutableSetRef _commonModes; / set 中保存的就是 NSRunLoopCommonModes 表示的 mode,我们也可以将自定义的 mode 添加到这个 set 里。CFMutableSetRef _commonModeItems; /添加到 NSRunLoopCommonModes 中的source/timer 等 item 都会被添加到这个 set 里,这在应用场景一中有打印出来。CFRunLoopModeRef _currentMode; /RunLoop 当前执行的是哪个 modeCFMutableSetRef _modes; / 该 runLoop 中所有的 modestruct _block_item *_blocks_head;struct _block_item *_blocks_tail;CFAbsoluteTime _runTime;CFAbsoluteTime _sleepTime;CFTypeRef _counterpart;再来看一下 RunLoopMode 的结构,之前说过 RunLoopMode 中存放的是两种source/timer/observer,而 CFRunLoopModeRef 是 struct _CFRunLoopMode *重命名的(typedef struct _CFRunLoopMode *CFRunLoopModeRef;), 看下定义就明白了:struct _CFRunLoopMode CFRuntimeBase _base;pthread_mutex_t _lock; /* must have the run loop locked before locking this */CFStringRef _name; /mode 的 nameBoolean _stopped;char _padding3;CFMutableSetRef _sources0; / 保存所有 source0 的 setCFMutableSetRef _sources1; / 保存所有 source1 的 set CFMutableArrayRef _observers; / 保存所有 observer 的数组CFMutableArrayRef _timers; / 保存所有 timer 的数组CFMutableDictionaryRef _portToV1SourceMap;_CFPortSet _portSet;CFIndex _observerMask;#if USE_DISPATCH_SOURCE_FOR_TIMERSdispatch_source_t _timerSource;dispatch_queue_t _queue;Boolean _timerFired; / set to true by the source when a timer has firedBoolean _dispatchTimerArmed;#endif#if USE_MK_TIMER_TOOmach_port_t _timerPort;Boolean _mkTimerArmed;#endif#if DEPLOYMENT_TARGET_WINDOWSDWORD _msgQMask;void (*_msgPump)(void);#endifuint64_t _timerSoftDeadline; /* TSR */uint64_t _timerHardDeadline; /* TSR */;看完上面 _CFRunLoopMode 和 _CFRunLoop 的定义,关于 RunLoop 中保存的是RunLoopMode,而 RunLoopMode 中保存的才是实际的任务这点没有疑问了。如何创建一个 RunLoop?包括 MainRunLoop 在内,每一个 RunLoop 都与一个线程关联着。确切的说,是先有线程,再有 RunLoop。 关于线程与 RunLoop 的关系,在 RunLoop 官方文档的第一节讲的很清楚。 我们不用,也最好不要显示的创建 RunLoop,苹果提供了两个 API,便于我们来获取RunLoop。 CFRunLoopGetMain() 和 CFRunLoopGetCurrent(),分别用于获取 MainRunLoop 和当前线程的 RunLoop(在主线程中调用 CFRunLoopGetCurrent()与 CFRunLoopGetMain()获取的其实都是 MainRunLoop) 。先来看一下,这两个函数的源码实现:CFRunLoopRef CFRunLoopGetMain(void) CHECK_FOR_FORK();static CFRunLoopRef _main = NULL; / no retain needed/通过_CFRunLoopGet0 这个关键函数,取出 MainRunLoop。if (!_main) _main = _CFRunLoopGet0(pthread_main_thread_np(); / no CAS neededreturn _main;CFRunLoopRef CFRunLoopGetCurrent(void) CHECK_FOR_FORK();CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(_CFTSDKeyRunLoop);if (rl) return rl;/通过_CFRunLoopGet0 这个关键函数,取出当前 RunLoop。return _CFRunLoopGet0(pthread_self();从以上源码,可以看出 RunLoop 是通过 _CFRunLoopGet0 函数来获取的,并且以线程作为参数。 这个函数的作用与 通过 key 从 NSDictionary 获取 Value 极为相似。接下来,看一下 _CFRunLoopGet0 的实现(太长不想看,可以看下面的伪代码):static CFMutableDictionaryRef _CFRunLoops = NULL;static CFLock_t loopsLock = CFLockInit;/ should only be called by Foundation/ t=0 is a synwww.sm136.comonym for main thread that always worksCF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) if (pthread_equal(t, kNilPthreadT) t = pthread_main_thread_np();_CFLock(if (!_CFRunLoops) _CFUnlock(CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, CFRunLoopRef mainLoop = _CFRunLoopCreate(pthread_main_thread_np();CFDict
收藏 下载该资源
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号