Runloop源码分析(2)——Runloop获取

2021-01-20  本文已影响0人  无悔zero

在上一篇进行了Runloop初探,这篇就来看看Runloop的获取。

  1. 我们直接来看主线程的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;
}
  1. 内部调用_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;
}

总结

  1. RunLoop和线程一一对应,保存在__CFRunLoops全局字典中(线程为keyRunLoopvalue);
  2. 主线程RunLoop会在初始化__CFRunLoops时创建;
  3. 子线程RunLoop会在首次获取时创建;
  4. 当线程销毁时,对应的RunLoop也会销毁。

下一篇:Runloop执行流程

上一篇下一篇

猜你喜欢

热点阅读