NSThread使用总结

如果对线程了解不够清楚,在项目就使用线程,会给开发带来很多问题。所以在iphone的项目中使用线程,最好先学习Apple的线程开发向导。以下是自己开发过程中,使用线程遇到的问题,以及解决的方法。

第一个问题,为什么要使用线程。在解决这个问题之前,要先了解什么是线程。在官方的线程开发文档中有明确的定义:Threadsarearelativelylightweightwaytoimplementmultiplepathsofexecutioninsideofanapplication.(线程是一个相对轻量级的,在应用程序内部,实现执行的多条路径的方式。)。通俗的讲就是,程序中的函数调用是一步一步执行的,而线程可以让多个函数同时调用,根据内核程序的调度,在不同的时间执行不同的函数,结果就像是程序在执行的过程中同时开通了多条路径,而如果没有线程,程序只能走一条路径。所以线程就自然有下面的两个优点:

1)多线程可以提高应用程序的响应能力,也就是,有了多线程应用程序才能一边在后台处理数据,一边还能接受用户的输入响应。否则只能等数据处理完,才能接受用户的输入响应。

2)在多核系统中,多线程能够提高应用程序的实时行动。因为多线程可以安排程序多条执行路径,所以在多核环境下,每个核同时可以执行不同路径的代码,这样就提高了应用程序的执行能力,同时也缩短了执行时间。

那么已经可以下结论了,之所以使用多线程,无非是2个原因。

1)为了使应用程序在处理数据的同时,不影响用户对应用程序的正常操作,就要使用多线程。否则用户只能等待数据处理完毕,这往往是人们无法忍受的。

2)如果应用程序中有大量的IO中断(譬如文件的读写,网络的访问…),以及用户的大量输入,这样处理器为了等待这些中断,就会处于空闲状态。而多线程恰恰可以利用了这些空闲状态,让应用程序做一些必要的计算,可以大大提升应用程序的执行效率。

网络下载是程序设计中经常遇到的问题,根据前面的介绍,会发现这里就需要用到多线程。因为用户在程序从网络上下载数据的过程,不可能等待数据到达。那么就针对这个实例,来说明第二个问题如何使用线程。

解决第二个问题之前,要引入一个概念RunLoops。可能在做windows及linux线程开发的过程中,没有听过这个概念。所以这里非常有必要解释以下,其实根据官方文档的解释,我们可以完全理解Runloop的用途,以及它和线程的关系。

Arunloopisapieceofinfrastructureusedtomanageeventsarrivingasynchronouslyonathread.(一个Runloop是在线程中管理事件异步到达的基础设备)。这里就有一个问题了,什么是异步到达。这里有个例子可以形象的表述这个问题。假如你饿了想吃东西了,你可能会亲自出去一趟,到某个便利店买点东西,然后吃掉。还有一个方法就是,你打电话给某个便利店帮你送一份外卖,这是你只需要在家里等外卖的人,通知你就可以了。第二个方法就是所谓的异步。所以转到计算机程序设计里面,异步就是当主程序中执行某个方法的时候,主程序不需要知道这个方法什么时候执行完,而是这个方法执行完的时候通知主程序就可以了。

根据上面的介绍,你会发现在线程中,常常会有2中不同的方式执行线程中的代码。第一个,把你要执行的所有的代码都写入到线程中,这样自然写入的代码执行完毕,线程同时就结束了。而第二种方式是你在线程中开启了一个方法,这个方法可能是你开的另外一个线程,你不知道这个方法什么时候执行完,需要这个方法执行完时,通知你的主线程,那么主线程怎么知道什么时候应该结束那?这里就必须要用到runloop。Runloop正如他字面意思一样,就是提供一个循环,就是当有异步输入源的时候,就等待异步输入源的结束。一个Runloop也就是当没有事情要做的时候,它就使线程进入休眠,有事情做的时候就开启线程。所以你完全可以自己写代码按照Runloop的思想,实现线程中的异步输入源的控制。官方API也解释了Runloop的使用要求:

Youarenotrequiredtousearunloopwithanythreadsyoucreate

butdoingsocanprovideabetterexperiencefortheuser.

Runloopsmakeitpossibletocreatelong-livedthreadsthatuseaminimalamountofresources.

Becausearunloopputsitsthreadtosleepwhenthereisnothingtodo,

iteliminatestheneedforpolling,whichwastesCPUcyclesandpreventstheprocessoritselffromsleeping

andsavingpower.(你不必要求创建的每个线程都使用runloop,但是如果你这样做了,能够给使用者提供一个很好的经历。Runloops使创建一个长期生存的线程而使用很少的资源成为可能性。因为当线程没事可做的时候,一个runloop可以使线程休眠。同时,也取消了线程状态切换的需求,减少了CPU时间片,同时放置处理器休眠,并且节约了能量)。这里你就明白了为何苹果的工程师要为线程提供一个Runloop那,就是为了减少线程在等待异步时间的时候,对资源的消耗。所以如果理解了Runloop自然线程如何使用就显而易见了。下面的实例代码就是线程如何处理异步输入源的,以及Runloop在其中的作用:

- (void)asynchronousSource{ for (int i = 0; i < 100; i++) { NSLog(@"asynchronous input source run"); } [[NSThread currentThread] cancel]; } - (void)thread{ NSAutoreleasePool *pool=[[NSAutoreleasePool alloc]init]; [self performSelector:@selector(asynchronousSource) withObject:nil afterDelay:1]; NSLog(@"me"); BOOL done = NO; do{ // Start the run loop but return after each source is handled. SInt32 result = CFRunLoopRunInMode(kCFRunLoopDefaultMode, 1, 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; if ([_myThread isCancelled]) { done = YES; NSLog(@"thread exit"); } // Check for any other exit conditions here and set the // done variable as needed. } while (!done); // while (done) { // [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1]]; // if ([_myThread isCancelled]) { // finish = NO; // NSLog(@"thread exit"); // } // } [pool release]; }


这里Runloop是使用官方提供的corefunction中的函数实现的,而注释掉的代码是使用cocoa中的函数实现。如果要了解这两种实现方法,可以在API文档中找到详细的例子,这里不再赘余。

你可能感兴趣的:(NSThread使用总结)