runloop
runloop 死循环,运行循环, 事件循环。
我们打开手机,app一直运行不会退出,当我们操作app时,app会立即给我们相应的响应,依赖的就是runloop;
runloop 作用:
- 运行循环,保证线程不退出,一直运行
- 当任务来时,会唤醒线程执行任务
- 没有任务时,线程进入休眠状态,节省系统资源
在OSX/iOS 系统中,runloop相关对象:NSRunLoop 和 CFRunLoopRef。
CFRunloopRef源码
首先了解几个结构体
__CFRunLoop
- __CFRunLoop
- __CFRunLoopMode
- __CFRunLoopSource
- __CFRunLoopObserver
- __CFRunLoopTimer
struct __CFRunLoop {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* locked for accessing mode list */
__CFPort _wakeUpPort; // used for CFRunLoopWakeUp
Boolean _unused;
volatile _per_run_data *_perRunData; // reset for runs of the run loop
pthread_t _pthread; //runloop所在的线程 每一个runloop对应一个线程
uint32_t _winthread;
CFMutableSetRef _commonModes; // 存储commonMode中的mode 默认commonMode 中含有两个mode
CFMutableSetRef _commonModeItems; //存储commonModelItem中的(source, observer, timer)
CFRunLoopModeRef _currentMode; //runloop当前所在的mode
CFMutableSetRef _modes; //__CFRunLoopMode 一个线程中存在多个mode
struct _block_item *_blocks_head;
struct _block_item *_blocks_tail;
CFTypeRef _counterpart;
};
使用 timer需要加入到commonModel下 默认commonModel中包含kCFRunLoopDefaultMode 和 UITrackingRunLoopMode;
kCFRunLoopDefaultMode 正常状态, UITrackingRunLoopMode scrollView 滚动状态
__CFRunLoopMode
- 一个runloop 对应一个线程
- 一个runloop 中对应多个mode
- 切换mode需要退出当前mode,mode中的item时独立存在,在当前mode下只能处理当前mode对应的 commonModelItem,同一时间runloop只存在一种mode状态
- commonMode对应多个mode,添加进commonMode的item,循环添加进commonModel中所有mode中
struct __CFRunLoopMode {
CFRuntimeBase _base;
pthread_mutex_t _lock; /* must have the run loop locked before locking this */
CFStringRef _name;
Boolean _stopped;
char _padding[3];
CFMutableSetRef _sources0; //当前mode下source0
CFMutableSetRef _sources1; //当前mode下source1
CFMutableArrayRef _observers; //当前mode下observer
CFMutableArrayRef _timers; //当前mode下timer
CFMutableDictionaryRef _portToV1SourceMap;
__CFPortSet _portSet; //基于mach_port的source1
CFIndex _observerMask;
#if USE_DISPATCH_SOURCE_FOR_TIMERS
dispatch_source_t _timerSource;
dispatch_queue_t _queue;
Boolean _timerFired; // set to true by the source when a timer has fired
Boolean _dispatchTimerArmed;
#endif
#if USE_MK_TIMER_TOO
mach_port_t _timerPort;
Boolean _mkTimerArmed;
#endif
#if DEPLOYMENT_TARGET_WINDOWS
DWORD _msgQMask;
void (*_msgPump)(void);
#endif
uint64_t _timerSoftDeadline; /* TSR */
uint64_t _timerHardDeadline; /* TSR */
};
CF_INLINE void __CFRunLoopModeLock(CFRunLoopModeRef rlm) {
pthread_mutex_lock(&(rlm->_lock));
//CFLog(6, CFSTR("__CFRunLoopModeLock locked %p"), rlm);
}
- 可以多个 source0/source1,observer,timer,timer
- 当mode为__CFRunLoop的currentMode (source0/source1,observer,timer,timer )才会执行
__CFRunLoopSource
struct __CFRunLoopSource {
CFRuntimeBase _base;
uint32_t _bits;
pthread_mutex_t _lock;
CFIndex _order; /* immutable */
CFMutableBagRef _runLoops;
union {
CFRunLoopSourceContext version0; /* immutable, except invalidation */
CFRunLoopSourceContext1 version1; /* immutable, except invalidation */
} _context;
};
事件源,只有source0和source1
- Source0 只包含了一个回调(函数指针),它并不能主动触发事件。使用时,你需要先调用 CFRunLoopSourceSignal(source),将这个 Source 标记为待处理,然后手动调用 CFRunLoopWakeUp(runloop) 来唤醒 RunLoop,让其处理这个事件。
- source1包含一个mach_port和回调指针,source1用于内核和其他线程直接的消息,source1能唤醒线程。
__CFRunLoopObserver
struct __CFRunLoopObserver {
CFRuntimeBase _base;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop; //runloop 观察的runloop
CFIndex _rlCount;
CFOptionFlags _activities; /* immutable */ //runloop状态
CFIndex _order; /* immutable */
CFRunLoopObserverCallBack _callout; /* immutable */ 回调指针
CFRunLoopObserverContext _context; /* immutable, except invalidation */
};
__CFRunLoopObserver 包含观察的runloop 和回调指针,当runloop状态变化时,回调用回调函数 回调时间点
typedef CF_OPTIONS(CFOptionFlags, CFRunLoopActivity) {
kCFRunLoopEntry = (1UL << 0), // 即将进入Loop
kCFRunLoopBeforeTimers = (1UL << 1), // 即将处理 Timer
kCFRunLoopBeforeSources = (1UL << 2), // 即将处理 Source
kCFRunLoopBeforeWaiting = (1UL << 5), // 即将进入休眠
kCFRunLoopAfterWaiting = (1UL << 6), // 刚从休眠中唤醒
kCFRunLoopExit = (1UL << 7), // 即将退出Loop
};
__CFRunLoopTimer
struct __CFRunLoopTimer {
CFRuntimeBase _base;
uint16_t _bits;
pthread_mutex_t _lock;
CFRunLoopRef _runLoop; //runloop
CFMutableSetRef _rlModes; //加入的mode
CFAbsoluteTime _nextFireDate;
CFTimeInterval _interval;//间隔 /* immutable */
CFTimeInterval _tolerance;//误差 /* mutable */
uint64_t _fireTSR; /* TSR units */
CFIndex _order; /* immutable */
CFRunLoopTimerCallBack _callout; /* immutable */ //回调
CFRunLoopTimerContext _context; /* immutable, except invalidation */
};
CFRunLoopTimerRef 是基于时间的触发器,它和 NSTimer 是toll-free bridged 的,可以混用。其包含一个时间长度和一个回调(函数指针)。当其加入到 RunLoop 时,RunLoop会注册对应的时间点,当时间点到时,RunLoop会被唤醒以执行那个回调。
他们的关系是:
参考资料: