跳转至

线程保活

子线程执行完任务之后就会自动销毁,频繁的创建和销毁线程会有资源浪费。使用runloop让线程长时间存活,而不被自动销毁。

线程和runloop是一对一的关系。

创建runloop:[NSRunLoop currentRunLoop]

runloop中如果没有source timer observer,[[NSRunLoop currentRunLoop] run];会直接休眠。加入到当前的线程就没有用了,虽然存在,但是加入到当前子线程的任务不会执行。

三种方法:

[[NSRunLoop currentRunLoop] addPort:[NSPort port] forMode:NSRunLoopCommonModes];

[[NSRunLoop currentRunLoop] addTimer:<#(nonnull NSTimer *)#> forMode:<#(nonnull NSRunLoopMode)#>];

CFRunLoopAddSource(<#CFRunLoopRef rl#>, <#CFRunLoopSourceRef source#>, <#CFRunLoopMode mode#>);

子线程需要加port事件源保活,主线程不需要source0 source1 timer observer保活。

// expects rl and rlm locked
static Boolean __CFRunLoopModeIsEmpty(CFRunLoopRef rl, CFRunLoopModeRef rlm, CFRunLoopModeRef previousMode) {
    CHECK_FOR_FORK();
    if (NULL == rlm) return true;
#if DEPLOYMENT_TARGET_WINDOWS
    if (0 != rlm->_msgQMask) return false;
#endif

    //主线程
    Boolean libdispatchQSafe = pthread_main_np() && ((HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && NULL == previousMode) || (!HANDLE_DISPATCH_ON_BASE_INVOCATION_ONLY && 0 == _CFGetTSD(__CFTSDKeyIsInGCDMainQ)));
    if (libdispatchQSafe && (CFRunLoopGetMain() == rl) && CFSetContainsValue(rl->_commonModes, rlm->_name)) return false; // represents the libdispatch main queue

    //子线程:三个判断
    if (NULL != rlm->_sources0 && 0 < CFSetGetCount(rlm->_sources0)) return false;
    if (NULL != rlm->_sources1 && 0 < CFSetGetCount(rlm->_sources1)) return false;
    if (NULL != rlm->_timers && 0 < CFArrayGetCount(rlm->_timers)) return false;
    struct _block_item *item = rl->_blocks_head;
    while (item) {
        struct _block_item *curr = item;
        item = item->_next;
        Boolean doit = false;
        if (CFStringGetTypeID() == CFGetTypeID(curr->_mode)) {
            doit = CFEqual(curr->_mode, rlm->_name) || (CFEqual(curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(rl->_commonModes, rlm->_name));
        } else {
            doit = CFSetContainsValue((CFSetRef)curr->_mode, rlm->_name) || (CFSetContainsValue((CFSetRef)curr->_mode, kCFRunLoopCommonModes) && CFSetContainsValue(rl->_commonModes, rlm->_name));
        }
        if (doit) return false;
    }
    return true;
}
      ┌────────────────────────────────────┐
      │ __CFRunLoopModeIsEmpty(rl, rlm, ...)│
      └────────────────────────────────────┘
                     │
                     ▼
          ┌──────────────────┐
          │ rlm == NULL ?     │───Yes──→ 返回 TRUE (空)
          └──────────────────┘
                     │No
                     ▼
      ┌─────────────────────────────────────┐
      │[Windows] rlm->_msgQMask != 0 ?       │───Yes──→ 返回 FALSE (非空)
      └─────────────────────────────────────┘
                     │No
                     ▼
          ┌─────────────────────────────────────────────────────────────┐
          │ 计算 libdispatchQSafe (判断是否主线程且 main queue 可安全执行) │
          └─────────────────────────────────────────────────────────────┘
                     │
                     ▼
   ┌─────────────────────────────────────────────────────────┐
   │ libdispatchQSafe && rl 是 MainRunLoop                    │
   │ && 当前 mode 在 rl->_commonModes 中 ?                    │
   └─────────────────────────────────────────────────────────┘
                     │Yes
                     ▼
              返回 FALSE (非空,main queue 有任务)
                     │No
                     ▼
    ┌─────────────────────────────────────────┐
    │ rlm->_sources0 有元素?                  │──Yes→ 返回 FALSE
    ├─────────────────────────────────────────┤
    │ rlm->_sources1 有元素?                  │──Yes→ 返回 FALSE
    ├─────────────────────────────────────────┤
    │ rlm->_timers 有元素?                    │──Yes→ 返回 FALSE
    └─────────────────────────────────────────┘
                     │No
                     ▼
   ┌────────────────────────────────────────────────────┐
   │ 遍历 rl->_blocks_head 链表                          │
   │ 检查 block 绑定的 mode 是否与 rlm->_name 匹配        │
   │ 或 commonModes 匹配                                 │
   └────────────────────────────────────────────────────┘
                     │匹配
                     ▼
              返回 FALSE (非空)
                     │无匹配
                     ▼
              返回 TRUE (空)

GCD和NSOperation都可以线程保活。

条件锁也可以进行线程保活。