RunLoop

作者: 草水唐 | 来源:发表于2016-04-23 19:35 被阅读0次

    RunLoop概述

    一般来讲,一个线程一次只能执行一个任务,执行完成后线程就会退出。如果我们需要一个机制,让线程能随时处理事件但并不退出,通常的代码逻辑是这样的:
    Event loop

    RunLoop和Thread

    • RunLoop和线程的关系:

    一个RunLoop对应着一条唯一的线程

    • RunLoop的创建:

    MainThread上的RunLoop默认是创建好并启动的,其它Thread中的RunLoop默认是没有创建RunLoop

    • RunLoop的生命周期:

    在第一次获取时创建,在线程结束时销毁。除了MainThread外,其它Thread首次获取该Thread的RunLoop时才被创建,代码流程见下面

    // 全局的 Dictionary ,key 是 pthread_t , value 是 CFRunLoopRef
    static CFMutableDictionaryRef loopsDic;
    // 访问 loopsDic 时的线程锁
    static CFSpinLock_t loopsLock;
    
    // 获取一个 pthread 对应的 RunLoop
    CFRunLoopRef _CFRunLoopGet(pthread_t thread) {
        OSSpinLockLock(&loopsLock);
    
        if (!loopsDic) {
            // 第一次进入时,初始化全局 Dic ,并先为主线程创建一个RunLoop
            loopsDic = CFDictionaryCreateMutable();       
            CFRunLoopRef mainLoop = _CFRunLoopCreate();
            CFDictionarySetValue(loopsDic, pthread_main_thread_np(), mainLoop);  
        }
    
        // 直接从 Dictionary 里获取 thread
        CFRunLoopRef loop = CFDictionaryGetValue(loopsDis, thread);
    
        if (!loop) {
            // 如果取不到,创建一个
            loop = _CFRunLoopCreate();
            CFDictionarySetValue(loopsDic, thread, loop);
            // 注册一个回调,当线程销毁时,顺便也销毁其对应的 RunLoop
            _CFSetTSD(..., thread, loop, __CFFinalizeRunLoop);
        }
    
        OSSpinLockUnLock(&loopsLock); 
        return loop;
    }
    

    从上面的代码可以看出,线程和RunLoop之间是一一对应的,其关系是保存在一个全局的Dictionary里。线程刚创建时并没有RunLoop,如果你不主动获取,那它一直都不会被创建。RunLoop的创建是发生在第一次获取时,RunLoop的销毁是发生在线程结束时。只能在一个线程的内部获取其RunLoop(MainThread除外)。

    注意:

    • 开一个子线程创建RunLoop,不是通过alloc init方法创建,而是直接通过调用currentRunLoop方法来创建,它本身是一个懒加载的。
    • RunLoop对象是利用字典来进行存储的,而且key是对应的Thread,value为该Thread对应的RunLoop
    • CFRunLoopRef源码可以在CoreFoundation源码中进行了解

    相关文章

      网友评论

          本文标题:RunLoop

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