Objective-C编程全解(第3版)19.1 多线程_Objective-C编程全解(第3版)19.1 多线程试读-查字典图书网
查字典图书网
当前位置: 查字典 > 图书网 > 编程 > Objective-C编程全解(第3版) > 19.1 多线程

Objective-C编程全解(第3版)——19.1 多线程

本章将说明使用线程进行并行处理的方法。首先会接触一 些基本的线程及锁的相关概念,然后再说明能够高效进行 并行化功能的类 NSOperation 的使用方法。最后介绍可以 在 MacOSX 中使用的连接的概况。 19.1 多线程 19.1.1 线程的基本概念 线程(thread)是进程(process)A 内假想的持有 CPU 使用权的执行单位。一般情况下,一个进程 只有一个线程,但也可以创建多个线程并在进程中并行执行。应用在执行某一处理的同时,还可以 接收 GUI 的输入。 使用多线程的程序称为多线程(multithread)运行。从程序开始执行时就运行的线程称为主线程, 除此之外,之后生成的线程称为次线程(secondarythread)或子线程(subthread)。 创建线程时,创建方的线程为父线程,被创建方的线程为子线程。父线程和子线程并行执行各 自的处理,但父线程可以等到子线程执行终止后与其会合(join)。而另一方面,在线程被创建后, 也可以切断父子关系指定它们不进行会合。该操作称为分离(detach)。这里所说的 NSThread 就是在 分离状态下创建线程。 由于被创建的线程共享进程的地址空间,所以能够自由访问进程的空间变量。多线程访问的变 。共享变量大多为全局变量或静态变量,但因为地址空间是共享的, 所以理论上所有内存区域都可以称为共享变量。 如果多线程胡乱访问共享变量,那么就不能保证变量值的正确性。所以有时就需要按照一定的 规则使多线程可以协调动作。此时就必须执行线程间互斥(或者排他控制,mutualexclusion)(见 。 各个线程都分配有栈且独立进行管理。基本上不能访问其他线程的栈内的变量(自动变量)。通 过遵守这样的编程方式,就可以自由访问方法或函数的自动变量,而且不用担心互斥。 使用引用计数管理方式时,为了使对象之间解耦合,子线程方需要创建与父线程不同的自动释 放池来管理。使用垃圾回收时不需要这样。 19.1.2 线程安全 多个线程同时操作某个实例时,如果没有得到错误结果或实例没有包含不正确的状态,那么该 类就称为线程安全(thread-safe)。结果不能保证时,则称为非线程安全或线程不安全(thread-unsafe)。 一般情况下,常数对象是线程安全的,变量对象不是线程安全的。常数对象可以在线程间安全 地传递,但对变量对象共享时,需要恰当地执行互斥或同步切换。 需要注意的是 C 语言的函数。就现状来看,BSD 函数的大部分,例如 printf() 等,都不是线程安 全的。 A 任务(task)这一名称也被用来表示与进程同样的概念,在苹果公司的文档“MultithreadingProgrammingTopics”中, 可以包含多线程的程序的执行单元称为进程,而任务则被用来抽象地表示应该进行的作业。 19.1.3 注意点 在某些情况下,使用多线程可以使处理高速化、实现易于使用的接口、使实现更简单等。但并 不是说使用多线程后就一定会得到这些优点。 要想使多线程程序不出错且高效执行,并行编程的知识必不可少。线程间的任务分配和信息交 换、共享资源的互斥、与 GUI 的交互及动画显示等,在使用时都要特别小心。 一般情况下,自己实现多线程程序是很困难的,而且也容易埋下高隐患。稍有差错或设计失误, 多 线 程 便 不 能 发 挥 效 果, 甚 至 还 会 导 致 未 知 原 因 的 释 放 或 异 常 终 止。 使 用 19.3 节 中 介 绍 的 NSOperation,虽然可以较容易地实现多线程程序,但是也必须掌握线程动作、互斥等相关知识。不 能适应这些的读者建议去参考一下并行编程的相关书籍。 而且,很多多线程中遇见的问题都可以通过 NSTimer 类或延迟消息发送(参考 15.1 节)来解决。 大家也不妨尝试一下用这些方法来解决相关问题。 19.1.4 使用 NSThread 创建线程 Foundation 框架中提供了 NSThread 类来创建并控制线程。该类的接口在 Foundation/NSThread.h 中声明。 创建新线程需要执行下面的类方法。 +(void)detachNewThreadSelector:(SEL)aSelector toTarget:(id)aTarget withObject: (id)anArgument 对 对象 aTarget 调用方法创建新线程并执行。选择器 aSelector 必须是仅获取一个 id 类型参数且返回值 为 void 的执行方法(参考 8.2 节)。 指定的方法执行结束后,线程也随之终止。线程从最初就被执行了分离,所以终止时没有和父 线程会合。当主线程终止时,包含子线程的程序也全部随之终止。 使用引用计数管理(手动及 ARC)时,有时需要执行的方法自身来管理自动释放池。此外,参 数 aTarget 和 anArgument 中指定的对象也与线程同时存在,即在创建线程时被保存,在线程终止时 被释放。 使用下述的 NSApplication 类中的方法也能创建线程。该方法使用上面的方法,而且在使用引用 计数管理时还会创建线程的自动释放池。 +(void)detachDrawingThread:(SEL)selector toTarget:(id)target withObject:(id)argument 创建新线程并执行的方法除了上述方法还有很多,本书中不再一一介绍。其他方法请参考 NSThread、NSObject 的参考文档。 程序可以调用 NSThread 类方法来确认是否是多线程运行。 +(BOOL)isMultiThreaded 多个线程并行执行时或者只有主线程在执行时,只要在此之前已经创建了线程,则返回 YES。 19.1.5 当前线程 一个线程称自身为当前线程(currentthread),区别于其他线程。 子线程将创建时指定的方法执行完后也会随之终止,但也可以中途终止。为此,可以使用当前 线程(线程自身)来执行下一个 NSThread 类方法。但是,使用引用计数管理时,终止前一定要释放 自动释放池。 +(void)exit 使用下述方法获得表示线程的 NSThread 实例。 +(NSThread*)currentThread 获 得表示当前线程的 NSThread 实例。 +(NSThread*)mainThread 获 得表示主线程的NSThread实例。查看当前线程是否为主线程时,可以使用类方法isMainThread。 每个线程都可以持有一个该线程固有的 NSMutableDictionary 类型的字典。向 NSThread 实例发 送下面的消息类就可以取得字典。 -(NSMutableDictionary*)threadDictionary 可以使当前线程仅被中断几秒。为此,可在当前线程中执行下面的类方法。参数为实数。 +(void) sleepForTimeInterval: (NSTimeInterval)ti 也可以使线程在某一时刻前中断,这时可采用下面的类方法。参数是表示日期的类 NSDate 实例。 +(void)sleepUntilDate:(NSDate*)aDate 如果要使线程到某个条件成立前一直保持休眠状态,则要使用下一章节介绍的锁。 19.1.6 GUI 应用和线程 在使用 GUI 的应用中,事件处理和绘图等大部分处理中线程都发挥了重要作用。也可以在子线 程中创建窗体,或分担部分绘图功能,但要注意避免竞争或内存泄漏。详情请参考相关文档。 GUI 应用中有较容易的方法来使用线程,即将 GUI 相关的时间处理或绘图集中在主线程中进行。 使用下面的方法,就可以从子线程依赖主线程中的方法处理。该方法为 NSOjbect 的范畴,在头文件 Foundation/NSThread.h 中声明。 -(void)performSelectorOnMainThread: (SEL)aSelector withObject: (id)arg waitUntilDone: (BOOL)wait 选 择器 aSelector 和参数 arg 中指定的方法的执行依赖于主线程。wait 为 YES 时,当前线程会一直等待 至执行结束。主线程中必须有事件循环(运行回路)。

展开全文

推荐文章

猜你喜欢

附近的人在看

推荐阅读

拓展阅读

《Objective-C编程全解(第3版)》其他试读目录

• 3.1 继承的概念
• 3.2 利用继承定义新类
• 3.3 使用继承的程序示例
• 3.4 继承和方法调用
• 3.5 方法定义时的注意事项
• 专栏:Objective-C 与开源软件
• 19.1 多线程 [当前]
• 19.2 互斥