美文网首页
Runloop源码分析(2)——Runloop获取

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

作者: 无悔zero | 来源:发表于2021-01-20 21:37 被阅读0次

    在上一篇进行了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执行流程

    相关文章

      网友评论

          本文标题:Runloop源码分析(2)——Runloop获取

          本文链接:https://www.haomeiwen.com/subject/glxlzktx.html