如何正确结束驱动RunLoop的ios nsthread结束线程

4068人阅读
iphone应用开发(2)
不负责任的apple sample
Apple的Sample说可以轮循线程是否应该退出,但是有bug
see:documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html
- (void)threadRuntime:(id)arg
@autoreleasepool {
GXLog(@&Thread created............&&&&&&&&&&&&&&&&&&&&&&&);
NSRunLoop *rl = [NSRunLoop currentRunLoop];
[_target performSelector:_selector withObject:arg];
[_target release];
BOOL exitNow = NO;
NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
[threadDict setValue:[NSNumber numberWithBool:exitNow] forKey:@&ThreadShouldExitNow&];
NSDate *date = [NSDate date];
while (!exitNow) {
[rl runUntilDate:date];
exitNow = [[threadDict valueForKey:@&ThreadShouldExitNow&] boolValue];
[_thread release];
GXLog(@&Thread Exited............&&&&&&&&&&&&&&&&&&&&&&&);
Instruments进行Time Profile是这样的:
做的题外的修改,如果这样轮询
while (!exitNow) {
[rl runUntilDate:[NSDate date]];
exitNow = [[threadDict valueForKey:@&ThreadShouldExitNow&] boolValue];
内存占用很恐怖
[NSDate date] autorelease来不及释放,程序最终会因为内存耗尽被系统干掉。
使用CFRunLoopRun/CFRunLoopStop正确结束NSThread
一切皆因轮询而起,那就破了轮询
- (void)threadRuntime:(id)arg
@autoreleasepool {
GXLog(@&Thread created............&&&&&&&&&&&&&&&&&&&&&&&);
[_target performSelector:_selector withObject:arg];
[_target release];
CFRunLoopRun();
[_thread release];
GXLog(@&Thread Exited............&&&&&&&&&&&&&&&&&&&&&&&);
- (void)stop
&&& if (!_thread) {
&&& CFRunLoopStop(CFRunLoopGetCurrent());
千万小心,stop会直接停止当前线程得RunLoop,这要求在RunLoop所在的线程执行stop, 实际情况可能在其它线程调用stop。
虽然cocoa&xcode有很多利器,但是能不用多线程还是别用吧。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:50622次
排名:千里之外
原创:21篇
(1)(2)(1)(2)(2)(1)(2)(1)(1)(3)(2)(2)(1)(2)(3)您所在的位置: &
iOS中多线程原理与runloop介绍
iOS中多线程原理与runloop介绍
iPhone中的线程应用并不是无节制的,官方给出的资料显示iPhone OS下的主线程的堆栈大小是1M,第二个线程开始都是512KB。并且该值不能通过编译器开关或线程API函数来更改。只有主线程有直接修改UI的能力。
一.线程概述
有些程序是一条直线,起点到终点;有些程序是一个圆,不断循环,直到将它切断。直线的如简单的Hello World,运行打印完,它的生命周期便结束了,像昙花一现那样;圆如操作系统,一直运行直到你关机。&
一个运行着的程序就是一个进程或者叫做一个任务,一个进程至少包含一个线程,线程就是程序的执行流。Mac和iOS中的程序启动,创建好一个进程的同时, 一个线程便开始运行,这个线程叫主线程。主线程在程序中的地位和其他线程不同,它是其他线程最终的父线程,且所有界面的显示操作即AppKit或 UIKit的操作必须在主线程进行。&
系统中的每一个进程都有自己独立的虚拟内存空间,而同一个进程中的多个线程则共用进程的内存空间。每创建一个新的线程,都需要一些内存(如每个线程有自己的Stack空间)和消耗一定的CPU时间。另外当多个线程对同一个资源出现争夺的时候需要注意线程安全问题。
二.创建线程
创建一个新的线程就是给进程增加了一个执行流,执行流总得有要执行的代码吧,所以新建一个线程需要提供一个函数或者方法作为线程的入口。
1.使用NSThread
NSThread提供了创建线程的途径,还可以提供了检测当前线程是否是主线程的方法。 使用NSThread创建一个新的线程有两种方式:
1.创建一个NSThread的对象,调用其start方法。对于这种方式的NSThread对象的创建,可以使用一个目标对象的方法初始化一个NSThread对象,或者创建一个继承NSThread类的子类,实现其main方法,然后在直接创建这个子类的对象。
2.使用&detachNewThreadSelector:toTarget:withObject:这个类方法创建一个线程,这个比较直接了,直接使用目标对象的方法作为线程启动入口。
2.使用NSObject
其实NSObject直接就加入了多线程的支持,允许对象的某个方法在后台运行。如:
[myObj&performSelectorInBackground:@selector(doSomething)&withObject:nil];&
3.POSIX Thread
由于Mac和iOS都是基于Darwin系统,Darwin系统的XUN内核,是基于Mach和BSD的,继承了BSD的POSIX接口,所以可以直接使用POSIX线程的相关接口来使用线程。
创建线程的接口为&pthread_create,当然在创建之前可以通过相关函数设置好线程的属性。以下为POSIX线程使用简单的例子。
三.多线程进阶
NSOperation&NSOperationQueue
很多时候我们使用多线程,需要控制线程的并发数,毕竟线程也是消耗系统资源的,当程序中同时运行的线程过多时,系统必然变慢。 所以很多时候我们会控制同时运行线程的数目。
NSOperation可以封装我们的操作,然后将创建好的NSOperation对象放到NSOperationQueue中,OperationQueue便开始启动新的线程去执行队列中的操作,OperationQueue的并发度是可以通过如下方式进行设置:
-&(void)setMaxConcurrentOperationCount:(NSInteger)count&
GCD是Grand Central Dispatch的缩写,是一系列的BSD层面的接口,在Mac 10.6
和iOS4.0以后才引入的,且现在NSOperation和NSOperationQueue的多线程的实现就是基于GCD的。目前这个特性也被移植到 FreeBSD上了,可以查看libdispatch这个开源项目。
比如一个在UIImageView中显示一个比较大的图片
dispatch_queue_t&imageDownloadQueue&=&dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,&0);&dispatch_async(imageDownloa&
当然,GCD除了处理多线程外还有很多非常好的功能,其建立在强大的kqueue之上,效率也能够得到保障。
四.线程间通信
线程间通信和进程间通信从本质上讲是相似的。线程间通信就是在进程内的两个执行流之间进行数据的传递,就像两条并行的河流之间挖出了一道单向流动长沟,使得一条河流中的水可以流入另一条河流,物质得到了传递。
1.performSelect On The Thread
框架为我们提供了强制在某个线程中执行方法的途径,如果两个非主线程的线程需要相互间通信,可以先将自己的当前线程对象注册到某个全局的对象中去,这样相 互之间就可以获取对方的线程对象,然后就可以使用下面的方法进行线程间的通信了,由于主线程比较特殊,所以框架直接提供了在出线程执行的方法。
@interface&NSObject&(NSThreadPerformAdditions)&-&(void)performSelectorOnMainThread:(SEL)aSelector&withObject:(id)arg&waitUnti&
&&&&&& 2.Mach Port&
在苹果的Thread Programming Guide的Run Pool一节的Configuring
a Port-Based Input Source 这一段中就有使用Mach Port进行线程间通信的例子。
其实质就是父线程创建一个NSMachPort对象,在创建子线程的时候以参数的方式将其传递给子线程,这样子线程中就可以向这个传过来的 NSMachPort对象发送消息,如果想让父线程也可以向子线程发消息的话,那么子线程可以先向父线程发个特殊的消息,传过来的是自己创建的另一个 NSMachPort对象,这样父线程便持有了子线程创建的port对象了,可以向这个子线程的port对象发送消息了。
当然各自的port对象需要设置delegate以及schdule到自己所在线程的RunLoop中,这样来了消息之后,处理port消息的delegate方法会被调用,你就可以自己处理消息了。
五.RunLoop
RunLoop从字面上看是运行循环的意思,这一点也不错,它确实就是一个循环的概念,或者准确的说是线程中的循环。 本文一开始就提到有些程序是一个圈,这个圈本质上就是这里的所谓的RunLoop,就是一个循环,只是这个循环里加入很多特性。&
首先循环体的开始需要检测是否有需要处理的事件,如果有则去处理,如果没有则进入睡眠以节省CPU时间。
所以重点便是这个需要处理的事件,在RunLoop中,需要处理的事件分两类,一种是输入源,一种是定时器,定时器好理解就是那些需要定时执行的操作,输 入源分三类:performSelector源,基于端口(Mach
port)的源,以及自定义的源。编程的时候可以添加自己的源。RunLoop还有一个观察者Observer的概念,可以往RunLoop中加入自己的 观察者以便监控着RunLoop的运行过程,CFRunLoop.h中定义了所有观察者的类型:
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的,除非你在一个单独的线程中需要长久的检测某个事件。【编辑推荐】【责任编辑: TEL:(010)】
关于&&&&的更多文章
Android 4.4即将发布,这对大家来说都是很期待的,当然,无论是
既然强大的Android Studio来了,有什么理由不去用呢?
越来越多的web设计师提出了移动优先的口号,而随着硬
北京时间日,苹果在加利福尼亚召开新品发
免费下载+应用内购买(In-App Purchase)已成为移动应用
本书主要介绍了在手机上开发J2ME游戏的方法,作者在介绍了J2ME游戏开发相关知识背景的基础上,以大富翁手机游戏的设计开发为例,
Windows Phone专家
Android开发专家
51CTO旗下网站&&&&RunLoop示例
RunLoop示例
《NSThread 、NSRunLoop 和 Dispatch Queue》一文示例源代码
若举报审核通过,可奖励20下载分
被举报人:
举报的资源分:
请选择类型
资源无法下载
资源无法使用
标题与实际内容不符
含有危害国家安全内容
含有反动色情等内容
含广告内容
版权问题,侵犯个人或公司的版权
*详细原因:
VIP下载&&免积分60元/年(1200次)
您可能还需要
移动开发下载排行ios 中runtime和runloop 的区别_百度知道
ios 中runtime和runloop 的区别
提问者采纳
&/zhidao/wh%3D450%2C600/sign=7d305bfca3c27d1ea158/e6a7ef6714417efafaaf51f3de66bc,负责处理UI事件,做一些额外的处理;&&&nbsp,无任何二义性,其中最主要的是消息机制;指向其父类& 主线程默认有Runloop,则取superClass中查找;&&struct&传递同步事件(重复执行或者在特定时间上触发),使用一个runLoop对象[NSRunloop currentRunloop]执行接收消息;表示该类为普通&&&;&&&nbsp,则存储对象方法;;&当事件再次发生时:&&&&objc_protocol_list&*ivars,也就是静态的Class,则该线程在执行完之后就退出了;//&Class&nbsp;&nbsp,OC可以调用任何函数;&/zhidao/wh%3D600%2C800/sign=6ac11f95fbe0e909b7a488fa/e6a7ef6714417efafaaf51f3de66&{&nbsp。OC的函数调用成为消息发送://b.&nbsp,需要为RunLoop添加至少一个事件源;&long&当没有事件发生时。对于一个类中;objc_class&nbsp。Runloop工作的特点,但是默认非主线程的RunLoop是没有运行的; 每一个线程都有其对应的RunL&//&&&nbsp:[objc]NSObject&&nbsp,从而达到省电的目的,有事件来临了;表示该类为&nbsp。在Class中先去cache中通过SEL查找对应函数method(猜测cache中method列表是以SEL为key通过hash表来存储的;&&nbsp.jpg" />注意;&&struct&;&//&&nbsp.jpg" target="_blank" title="点击查看大图" class="ikqb_img_alink"><img class="ikqb_img" src="version&nbsp,相同的方法名称只能对应一个SEL;}&nbsp,处理事件。然后我们看看Class?typedef&nbsp。假如在OC中写了这样的一个代码;&nbsp。与root class结构体成员一致,初始化默认为0;Class&&nbsp。Root metaclass是通过继承Root class产生的;&&&&&nbsp。& Runloop是事件接收和分发机制的一个实现;&&nsobject&gt,函数的调用在编译的时候会决定调用哪个函数( C语言的函数调用请看这里 ),即使这个函数并未实现;& RunLoop。&nbsp。[objc]&&nbsp。就是系统在运行的时候的一些机制,iOS中的obj都继承于NSO&&&nbsp。下面一张图片很好的描述了类和对象的继承关系.提示;&nbsp,makeText是一个函数名称。注册成为Runloop的struct&nbsp.jpg" esrc="http,如果这个类是根类;**methodLists&&CLS_META&nbsp。每一个方法对应着一个SEL;&nbsp。对于这样一个简单的调用,并通过method中的函数指针跳转到对应的函数中去执行。当自己启动一个线程;&&& input sources&nbsp,需要代码提供while或者for循环来驱动RunLstyle=&&&&nbsp,如CLS_CLASS&&Class&&&&nbsp。首先通过obj的isa指针找到obj对应的&&&&&nbsp,然后去run它;charchar&nbsp,普通Class中的isa指针指向静态Class。SEL其本身是一个Int类型的一个地址; Runloop提供了一种异步执行代码的机制,Runloop 也会产生一些关于本身行为的我们可以看到,对于一个Class类中;span&nbsp,用于提升效率.什么时候使用Runloop :18px,不能并行执行任务;&&nbsp,存在很多东西。再去methodList中查找; Runloop接收两种源事件,其中包含对象方法和成员变量; 在NSObjcet中存在一个Class的isa指针;&&/span&(0x1L)。而C语言在编译阶段就会报错);&nbsp,在编译阶段。所以当我们需要让该线程监听某项事务时, @selector (makeText)); &该类的实例变量大小(包括从父类继承下来的实例变量);& &&nbsp,调用对应的处理函数。对于C语言;& timer sources(定时器)& RunTime简称运行时,地址中存放着方法的名字,一直卡着。(使用CoreFoundation来成为runloop的observer);isa&&&nbsp,@selector(makeText));class&&&&nbsp,如CLS_META&&info&nbsp:&//&instance_size&&&nbsp,Main RunLoop直接配合任务的执行,是线程进入和被线程用来相应事件以及调用事件处理函数的地方;&& 这是一个SEL方法选择器,则将method加入到cache中:&&&&&nbsp,除非你在一个单独的线程中需要长久的检测某个事件;&nbsp。&&nbsp,只要申明过就不会报错;&nbsp.&&&&&nbsp,执行其对应的函数?&{&nbsp,下面我来一一解释一下;}&lt、定时器以及其他内核相关事件.& &&isa。(1),则存储类方法;传递异步事件,这样能提高函数查找速度);&OBJC_ISA_AVAILABILITY。属于动态调用过程;&nbsp,runloop就是这么一个循环;&&&&& 首先我们来看看obj这个对象; 2&&指向最近使用的方法的指针;&nbsp.objc_cache&&&&nbsp。&nbsp,通常是来自其他线程和不同的程序中的消息;(0x1L)&nbsp,可以接收到这些notification,则为NULL。&nbsp.二; 首先;&&nbsp,没有事件的时候;&&nbsp,Runloop会被重新唤醒;一些标识信息;&nbsp.存储该类遵守的协议&&& (2);&&nbsp。Class super_ 保证程序执行的线程不会被系统终止;&&&&nbsp。&&&&&&*Cfont-size。若能找到,以方便下次查找;&&[obj&& & 3& 其中obj是一个对象;&&& 那OC是怎么实现动态调用的呢:&&&//&nbsp。而跟metaclass则指向自身.&&nbsp,就得让线程一直不退出;转化为objc_msgSend(obj?& 当需要和该线程进行交互的时候才会使用Runloop,下面我们来看看:指向*protocols。下面我们就来看看具体消息发送之后是怎么来动态查找对应的方法的;&&&&与&nbsp.Runtime。&&nbsp。编译完成之后直接顺序执行,也就是前面提到的结构;struct&& 除了处理input sources;& 一般情况下我们是没有必要去启用线程的RunLoop的;(0x2L)&nbsp://b;用于存储每个成员变量的地址&&;&&nbsp。&const&nbsp。SEL其主要作用是快速的通过方法名字(makeText)查找到对应方法的函数指针;& 在这个循环中,可以通过runtime函数class_setVersion和class_getVersion进行修改;&nbsp://b;*name&&&nbsp.&nbsp,如CLS_CLASS&nbsp:一般在开发中很少会主动创建R 在主队列中;类的版本信息;&&指向metaclass&//&nbsp:指向父类;&&&long&nbsp,如果只是用于处理单一的事件,而通常会把事件添加到Runloop中;&&struct&&&nbsp,静态Class中存储static类型成员变量和类方法(“+”开头的方法);&(0x2L),Runloop会进入休眠状态; &nbsp,这个Class中存储普通成员变量和对象方法(“-”开头的方法);&struct&nbsp,若methodlist中未找到。所以iOS类中不能存在2个名称相同的方法;&类名&nbsp.RunLoop的主要目的.com/zhidao/pic/item/e6a7ef6714417efafaaf51f3de66bc?@interface&nbsp.需要在代码中使用控制语句实现RunLoop的循环;的一些标志位有关,也就是说;& &&&nbsp,然后调用其函数。只有在真正运行的时候才会根据函数的名称找到对应的函数来调用;//&&&;makeText];&&当有时间发生时:input sources和timer sources。&&&objc_method_list&&nbsp。在编译的时候并不能决定真正调用哪个函数(事实证明;long&&* &nbsp,其中包含类方法?objc_msgSend( 1&&&&nbsp,Runloop会根据具体的事件类型通知应用程序作出相应、读取&;&nbsp。Class类中其他的成员这里就先不做过多解释了,正如其名所示;//&&nbsp。&nbsp?下面我们来看看OC通过发送消息来达到动态调用的秘密。不同的是Root metaclass的isa指针指向自身;&nbsp,因为SEL是根据方法名字生成的,编译器将代码[obj makeText];&nbsp:[objc]&objc_class&nbsp。在编译时RunTime会将上述代码转化成[objc] &super_class&&&nbsp./nsobject&&nbsp。一般一个Obj对象中的isa会指向普通的C&info:Class isa:&&//&//&&nbsp:<a href="http:所有metaclass中isa指针都指向跟&nbsp,即使参数类型不同;,若cache中未找到;objc_ivar_list&nbsp.RunL&nbsp,在objc_msgSend函数中;&nbsp:@selector (makeText)一
来自团队:
其他类似问题
为您推荐:
其他1条回答
这个线程只能是跑完一次任务,我们还是在运行一些长线任务或者复杂任务的时候需要用比较原始的NSThreadIPhone多线程编程提议用NSOperation和NSOperationQueue.因为如果我们用现有的线程函数的话,就释放所占有的资源了,这个确实很好用。这就需要为NSThread创建一个runloop。但是有些情况下
runtime的相关知识
等待您来回答
下载知道APP
随时随地咨询
出门在外也不愁

我要回帖

更多关于 nstimer runloop 的文章

 

随机推荐