Runloop
来源:互联网 发布:淘宝卖的夜磨牙垫好吗 编辑:程序博客网 时间:2024/04/29 03:47
RunLoops
概念
runloop是线程相关的基础对象,runloop是一个被用来处理事件或者timer的循环,runloop的目的是用来让线程在需要的时候运行,并且在不需要的时候休眠。
runloop的控制并不是自动的,你必须要手动管理。cocoa 和 foundation 提供了runloop对象来帮助你管理runloop,因而你不用创建。比如主线程就有自己的runloop,并且是自动运行的。子线程的runloop需要手动运行。需要注意的是,framwork的线程会自动建立并且作加入到主线程中作为应用的启动。
runloop分解
runloop就像他的名字一样是一个不断循环运行的环,runloop可以接受两种数据来源,
1. input source,可能是来源于其他线程的数据 会导致执行runUntilDate 执行
2. timer 不会导致执行runUntilDate 执行
除了可以处理输入的source,通过注册观察者也可以拿到runloop的通知代理。
runloop mode
mode可以很好的把事件和timer进行分类,这样可以更好地处理和管理不同类型的数据源,
cocoa 和 coreFoundation 可以创建一些默认的或者一些其他常用的mode。当然也可以自定义一个mode,但是所有的mode的runloop都是一样的只是名字不同。
同一时间只能进入一个mode,所以可以优先处理高优先级的mode,等待优先级高的mode结束之后再处理其他mode
几种不同的mode
input sources
port-based sources
cocoa和corefoundation 中corefondation需要创建port和source 需要使用port对象进行管理。
custom input source
使用 CFRunLoopSourceRef 创建相关的对象和回调方法,那么cf就会自动在指定时间调用这些回调,从而可以配置source
事件到达时需要自定义转发机制,这部分需要提供数据源和转发机制。
Cocoa Perform Selector Sources
使用一些api完成进程通讯,可以减轻很懂工作,并且可以自动移除source
在子线程中必须自己启动runloop,或者你甚至可以在程序一启动就立刻开启一个runloop,这样的话,你就可以一直在这个线程去做数据处理了。
TImer source
timer 的运行必须在runloop相同的mode下,并且需要等待runloop结束当前的handler处理才会执行。
timer的执行并不会按照fire的时间,而是以schedule 的时间为准。
NSMachPort
创建np(NSMachPort)并且添加到runloop中,添加子线程时将np传给子线程,子线程也可以用这个np去传递消息回来。
首先NSMarchPort是一个task内线程之间异步通信用的
你需要在你的两个object内重写handlePortMessage:方法来截取接收到的消息,使用NSPortMessage来发送消息
消息一般都是有唯一id和数据组成的
数据需要经过序列化通过NSPortMessage的components来传递
接收到数据之后需要进行反序列化
runloop 的观察者
可以添加一些runloop的观察者,这样就可以在指定时间观察到runloop的执行步骤,并且在这些步骤中做一些准备工作。你可以检测到的runloop执行
1. 开始
2. timer执行
3. inputsource 执行
4. 休眠前
5. 唤醒前。
6. 退出。
可以通过CFRunLoopObserverRef,使用例程
- (void)threadMain{ // The application uses garbage collection, so no autorelease pool is needed. NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop]; // Create a run loop observer and attach it to the run loop. CFRunLoopObserverContext context = {0, self, NULL, NULL, NULL}; CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault, kCFRunLoopAllActivities, YES, 0, &myRunLoopObserver, &context); if (observer) { CFRunLoopRef cfLoop = [myRunLoop getCFRunLoop]; CFRunLoopAddObserver(cfLoop, observer, kCFRunLoopDefaultMode); } // Create and schedule the timer. [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(doFireTimer:) userInfo:nil repeats:YES]; NSInteger loopCount = 10; do { // Run the run loop 10 times to let the timer fire. [myRunLoop runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; loopCount--; } while (loopCount);}
runloop的执行过程
runloop的观察者虽然可以检测到runloop的执行步骤,但是由于是异步检查,所以时间可能不会非常精准,可以使用awake-from-sleep notification
去校准时间。
我们可以使用runloop对象直接唤醒,但是也可以直接给他一个inputsource,runtime也会被唤醒执行任务。
什么时候会使用一个runloop呢?
程序的主线程无需启动,因为会自动创建,runloop也会自动创建。
对于子线程,如果你需要更加自由的配置runloop,那么你可能就需要自己管理了。比如如下的场景你可能就需要使用runloop了
- 线程间的通讯,或者自定义输入源
- timers
- perforselector
- 保存一个线程一直运行。
必须恰当的关闭一个线程,从而避免内存泄露
如何使用一个runloop
runloop是一个用来管理线程的对象,可以给线程添加事件来源,timer来源,runloop观察者,一个线程都有一个唯一的runloop,可以用 currentRunLoop
获取。
配置runloop
在runloop开始前,必须给其添加事件源,不然runloop就会直接休眠了。
初次之外,也可以添加观察者到runloop,这样就可以监测runloop的执行,如上一个代码片。
当需要保持一个长执行的runloop的时候,最好添加一个inputsorce来接受和发送信息。虽然一个repeqt timer也可以做到,但是不如inputsource效率高。
开启runloop
可以用以下三种方式开启runloop
无条件开启
无条件开启会导致runloop一直运行,而且无法控制设置一个时间期限
在deadline到来之前或者Event到来之前,runloop会一直执行。当有事件的时候,runloop就会把事件分发给处理着,然后退出。然后就可以执行下一个任务了。以某个mode开启。
除了使用timeout也可以使用mode开启runloop
使用的大概方式
例子使用了CFRunloopMode
- (void)skeletonThreadMain{ // Set up an autorelease pool here if not using garbage collection. BOOL done = NO; // Add your sources or timers to the run loop and do any other setup. do { // Start the run loop but return after each source is handled. SInt32 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 10, YES); // If a source explicitly stopped the run loop, or if there are no // sources or timers, go ahead and exit. if ((result == kCFRunLoopRunStopped) || (result == kCFRunLoopRunFinished)) done = YES; // Check for any other exit conditions here and set the // done variable as needed. } while (!done); // Clean up code here. Be sure to release any allocated autorelease pools.}
结束runloop
有两种方法可以结束runloop
- 设定超时
- 手动结束
设定超时是比较好的一种方法,可以让runloop尽量回收他的资源,并且完成包括notification等的执行过程。
使用CFRunloopStop会让runloop像timeout一样结束,可以让他在结束之前完成notification等动作再结束。
移除输入源虽然可以让runloop停止,但是这个方法并不可靠,因为有可能有一些inputsource你并不知道。
线程安全和runloop对象
Core Foundation 中的api一般都是线程安全的,并且可以在任何runloop中使用,包括你不控制的runloop。
NSRunloop 中的API最好只用在你管理的runloop里面。
- runloop
- runloop
- runloop
- RunLoop
- RUNLOOP
- RunLoop
- RunLoop
- RunLoop
- runloop
- RunLoop
- runloop
- runloop
- runloop
- runloop
- Runloop
- RunLoop
- RunLoop
- runloop
- Linux的vi模式下的快捷键
- 多线程数据同步
- HTML 音频
- 面向对象2
- Web服务器份额排行榜
- Runloop
- 浏览器跨域请求之credentials
- Android UI 之 Tab类型界面总结
- 【58】Spring总结之注解(2)
- ORACLE的Packge
- Linux驱动之输入子系统
- 高精度正整数乘法问题
- bzoj2251 外星联络
- COCOS 屏蔽一个layer