IOS多线程编程笔记与NSRunLoop学习

多线程与NSLoop笔记;
1.虽然operation objects和dispatch queue提供了更加现代化的多核并发操作,但mac os和iOS也提供直接操作和管理线程的接口,如果正在创建新的应用程序,苹果建议我们使用gcd或operation objects;除此之外还有:
1)idle-time notifications,当前程序的run loop空闲时会发出该通知,适合处理一些低优先级的短作业;
2)调用系统提供的异步api,不需要自己去考虑线程层次的问题;
3)定时器;
4)分离的单独进程;在某些时候需要使用,比如需要特定权限的作业可能需要另起进程。
2.mac os/ios中使用到的线程技术包括:
1)cocoa threads;这是oc的类库,主要有NSThread类;
2)POSIX threads;这是c的函数库,支持POSIX接口,POSIX标准定义了操作系统应该为应用程序提供的接口标准,POSIX标准意在期望获得源代码级别的软件可移植性。换句话说,为一个POSIX兼容的操作系统编写的程序,应该可以在任何其它的POSIX操作系统上编译执行。POSIX并不局限于UNIX。许多其它的操作系统,例如DEC OpenVMS支持POSIX标准;
3.一个run loop是用来在线程上管理事件异步到达的基础设施。一个run loop为线程监测一个或多个事件源。当事件到达的时候,系统唤醒线程并调度事件到run loop,然后分配给指定程序。如果没有事件出现和准备处理,run loop把线程置于休眠状态。配置run loop需要:
1)创建并启动线程;
2)获取run loop的对象引用;
3)设置事件处理程序,并告诉run loop运行;
4.cocoa会自动为你的主线程配置run loop,如果你打算创建长时间运行的辅助线程,你必须为你的线程配置相应的run loop。使用run loop 的目的是让你的线程在有工作的时候忙于工作,而没工作的时候处于休眠状态。
5.run loop的管理并不完全自动,你仍然需要设计你的线程代码在合适的时候启动run loop并正确响应输入事件。你的代码要提供实现循环部分的控制语句,换言之就是要有while或for循环语句来驱动run loop。在你的循环中,使用run loop object来运行事件处理代码,它响应接收到的事件并启动已经安装的处理程序。
6.仅当在为你的程序创建辅助线程的时候,你才可能需要显式运行一个run loop,一般不需要使用,了解其概念即可,只有如下情况才可能需要使用:
1)使用端口或自定义输入源和其它线程通信;
2)使用线程的定时器;
3)Cocoa中使用任何performSelector…的方法;
4)使线程周期性工作;

7.总体而言Run loop和线程编程的内容比较难懂,可以在遇到维护类似代码时,去参考苹果的多线程编程文档,新写的代码都不再使用之为好,加上dispatch sources可代替Run loop的情况下,更加没有必要使用之。NSRunLoop对象比CFRunLoop的c函数更加易于使用,可以获取currentRunLoop并调用addPort:forMode或addTimer:forMode往它上面添加事件,不过它是非线程安全的,也就是不要在NSRunLoop所在的线程之外去获取和改变其它属性,可能结果无法预知。

8.简单的runloop与thread的关系可以理解为,runloop负责管理线程while循环中的部分代码,线程在while中通过判断runloop是否有输入等的条件,runloop所封装的代码块等来达到一直循环处理事件的效果,同时runloop在没有事件时,也可以通知线程休眠。

【摘录网上找到的资料,感觉比较能理解】RunLoop

RunLoop从字面上看是运行循环的意思,这一点也不错,它确实就是一个循环的概念,或者准确的说是线程中的循环。 本文一开始就提到有些程序是一个圈,这个圈本质上就是这里的所谓的RunLoop,就是一个循环,只是这个循环里加入很多特性。 
首先循环体的开始需要检测是否有需要处理的事件,如果有则去处理,如果没有则进入睡眠以节省CPU时间。 所以重点便是这个需要处理的事件,在RunLoop中,需要处理的事件分两类,一种是输入源,一种是定时器,定时器好理解就是那些需要定时执行的操作,输 入源分三类:performSelector源,基于端口(Mach port)的源,以及自定义的源。编程的时候可以添加自己的源。RunLoop还有一个观察者Observer的概念,可以往RunLoop中加入自己的 观察者以便监控着RunLoop的运行过程,CFRunLoop.h中定义了所有观察者的类型:

  1. enum CFRunLoopActivity { kCFRunLoopEntry = (1 << 0), kCFRunLoopBeforeTimers = (1 << 1), kCFRunLoopBeforeSources = ( 

如果你使用过select系统调用写过程序你便可以快速的理解runloop事件源的概念,本质上讲事件源的机制和select一样是一种多路复用IO的 实现,在一个线程中我们需要做的事情并不单一,如需要处理定时钟事件,需要处理用户的触控事件,需要接受网络远端发过来的数据,将这些需要做的事情统统注 册到事件源中,每一次循环的开始便去检查这些事件源是否有需要处理的数据,有的话则去处理。 拿具体的应用举个例子,NSURLConnection网络数据请求,默认是异步的方式,其实现原理就是创建之后将其作为事件源加入到当前的 RunLoop,而等待网络响应以及网络数据接受的过程则在一个新创建的独立的线程中完成,当这个线程处理到某个阶段的时候比如得到对方的响应或者接受完 了网络数据之后便通知之前的线程去执行其相关的delegate方法。所以在Cocoa中经常看到scheduleInRunLoop:forMode: 这样的方法,这个便是将其加入到事件源中,当检测到某个事件发生的时候,相关的delegate方法便被调用。对于CoreFoundation这一层而 言,通常的模式是创建输入源,然后将输入源通过CFRunLoopAddSource函数加入到RunLoop中,相关事件发生后,相关的回调函数会被调 用。如CFSocket的使用。 另外RunLoop中还有一个运行模式的概念,每一个运行循环必然运行在某个模式下,而模式的存在是为了过滤事件源和观察者的,只有那些和当前 RunLoop运行模式一致的事件源和观察者才会被激活。

每一个线程都有其对应的RunLoop,但是默认非主线程的RunLoop是没有运行的,需要为RunLoop添加至少一个事件源,然后去run它。一般情况下我们是没有必要去启用线程的RunLoop的,除非你在一个单独的线程中需要长久的检测某个事件。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章