Runloop源码分析(2)——Runloop获取
2021-01-20 本文已影响0人
无悔zero
在上一篇进行了Runloop初探,这篇就来看看Runloop的获取。
- 我们直接来看主线程的
Runloop
获取:
CFRunLoopRef CFRunLoopGetMain(void) {
CHECK_FOR_FORK();
static CFRunLoopRef __main = NULL; // no retain needed
if (!__main) __main = _CFRunLoopGet0(pthread_main_thread_np()); // no CAS needed
return __main;
}
- 内部调用
_CFRunLoopGet0
获取主线程的Runloop
:
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
// 如果线程为空,默认视作主线程
if (pthread_equal(t, kNilPthreadT)) {
t = pthread_main_thread_np();
}
__CFLock(&loopsLock);
// __CFRunLoops用来保存RunLoop。判断没有就新建一个,并创建主线程对应的runloop
if (!__CFRunLoops) {
__CFUnlock(&loopsLock);
CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());// 创建主线程对应的runloop
CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);// 保存主线程runloop
if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {
CFRelease(dict);
}
CFRelease(mainLoop);
__CFLock(&loopsLock);
}
CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));// 根据线程取其对应的runloop
__CFUnlock(&loopsLock);
// 如果子线程没有对应的runloop,就新建一个runloop对象(懒加载)
if (!loop) {
CFRunLoopRef newLoop = __CFRunLoopCreate(t);//新建runloop
__CFLock(&loopsLock);
loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
if (!loop) {
CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);//保存runloop
loop = newLoop;
}
// don't release run loops inside the loopsLock, because CFRunLoopDeallocate may end up taking it
__CFUnlock(&loopsLock);
CFRelease(newLoop);
}
if (pthread_equal(t, pthread_self())) {
_CFSetTSD(__CFTSDKeyRunLoop, (void *)loop, NULL);
if (0 == _CFGetTSD(__CFTSDKeyRunLoopCntr)) {
_CFSetTSD(__CFTSDKeyRunLoopCntr, (void *)(PTHREAD_DESTRUCTOR_ITERATIONS-1), (void (*)(void *))__CFFinalizeRunLoop);// 注册一个回调,当线程销毁时一同销毁对应的runloop
}
}
return loop;
}
总结
RunLoop
和线程一一对应,保存在__CFRunLoops
全局字典中(线程为key
,RunLoop
为value
);- 主线程
RunLoop
会在初始化__CFRunLoops
时创建;- 子线程
RunLoop
会在首次获取时创建;- 当线程销毁时,对应的
RunLoop
也会销毁。
下一篇:Runloop执行流程。