深入浅出 RunLoop(四):RunLoop 与线程

2020/2/28 23:15:26

本文主要是介绍深入浅出 RunLoop(四):RunLoop 与线程,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

RunLoop 系列文章

深入浅出 RunLoop(一):初识
深入浅出 RunLoop(二):数据结构
深入浅出 RunLoop(三):事件循环机制
深入浅出 RunLoop(四):RunLoop 与线程
深入浅出 RunLoop(五):RunLoop 与 NSTimer
深入浅出 RunLoop(六):相关面试题

RunLoop 与线程的关系

苹果官方文档中,RunLoop的相关介绍写在线程编程指南中,可见RunLoop和线程的关系不一般。Threading Programming Guide(苹果官方文档)

  • RunLoop对象和线程是一一对应关系;
  • RunLoop保存在一个全局的Dictionary里,线程作为keyRunLoop作为value
  • RunLoop创建时机:线程刚创建时并没有RunLoop对象,RunLoop会在第一次获取它时创建(获取方式已经在《深入浅出 RunLoop(一):初识》文章中讲到);
  • RunLoop销毁时机:RunLoop会在线程结束时销毁;
  • 主线程的RunLoop已经自动获取(创建),子线程默认没有开启RunLoop
  • 主线程的RunLoop对象是在UIApplicationMain中通过[NSRunLoop currentRunLoop]获取,一旦发现它不存在,就会创建RunLoop对象。

开启子线程的 RunLoop 的过程

获取 RunLoop 对象

可以通过以下方式来获取RunLoop对象:

    // Foundation
    [NSRunLoop mainRunLoop];     // 获取主线程的 RunLoop 对象
    [NSRunLoop currentRunLoop];  // 获取当前线程的 RunLoop 对象
    // Core Foundation
    CFRunLoopGetMain();     // 获取主线程的 RunLoop 对象
    CFRunLoopGetCurrent();  // 获取当前线程的 RunLoop 对象
复制代码

我们来看一下CFRunLoopGetCurrent()函数是怎么获取RunLoop对象的:

CFRunLoopRef CFRunLoopGetCurrent(void) {
    CHECK_FOR_FORK();
    CFRunLoopRef rl = (CFRunLoopRef)_CFGetTSD(__CFTSDKeyRunLoop);
    if (rl) return rl;
    return _CFRunLoopGet0(pthread_self());  // 调用 _CFRunLoopGet0 函数并传入当前线程
}
复制代码
// should only be called by Foundation
// t==0 is a synonym for "main thread" that always works
CF_EXPORT CFRunLoopRef _CFRunLoopGet0(pthread_t t) {
    if (pthread_equal(t, kNilPthreadT)) {
	t = pthread_main_thread_np();
    }
    __CFLock(&loopsLock);
    if (!__CFRunLoops) {
        __CFUnlock(&loopsLock);
	CFMutableDictionaryRef dict = CFDictionaryCreateMutable(kCFAllocatorSystemDefault, 0, NULL, &kCFTypeDictionaryValueCallBacks);
	CFRunLoopRef mainLoop = __CFRunLoopCreate(pthread_main_thread_np());
	CFDictionarySetValue(dict, pthreadPointer(pthread_main_thread_np()), mainLoop);
	if (!OSAtomicCompareAndSwapPtrBarrier(NULL, dict, (void * volatile *)&__CFRunLoops)) {
	    CFRelease(dict);
	}
	CFRelease(mainLoop);
        __CFLock(&loopsLock);
    }
    // ️当前线程作为 Key,从 __CFRunLoops 字典中获取 RunLoop 
    CFRunLoopRef loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
    __CFUnlock(&loopsLock);
    if (!loop) {  // ️如果字典中不存在
	    CFRunLoopRef newLoop = __CFRunLoopCreate(t);  // 创建当前线程的 RunLoop
        __CFLock(&loopsLock);
	    loop = (CFRunLoopRef)CFDictionaryGetValue(__CFRunLoops, pthreadPointer(t));
    	if (!loop) {
	        CFDictionarySetValue(__CFRunLoops, pthreadPointer(t), newLoop);  // 保存到字典中
	        loop = newLoop;
    	}
        // don't release run loops inside the loopsLock, because CFRunLoopDe
                   

这篇关于深入浅出 RunLoop(四):RunLoop 与线程的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程