iOS 并行编程:Thread
1 创建线程
1.1 NSThread
使用 NSThread 来创建线程有两个可以使用的方法:
1) 使用 detachNewThreadSelector:toTarget:withObject:类方法来生成一个新的线程。
2) 创建一个新的 NSThread 对象,并调用它的 start 方法。
这两种创建线程的技术都在你的应用程序里面新建了一个脱离的线程。 一个脱离的线程意味着当线程退出的时候线程的资源由系统自动回收。
1 -(void) myThreadMainMethod
2 {
3 printf("myThreadMainMethod\n");
4 }
5
6 -(void) testMethod
7 {
8 NSThread* myThread = [[NSThread alloc] initWithTarget: self
9 selector:@selector(myThreadMainMethod)
10 object:nil];
11 [myThread start];
12 }
如果你拥有一个 NSThread 对象,它的线程当前真正运行,你可以给该线程发送消息的唯一方法是在你应用程序里面的任何对象使用performSelector:onThread:withObject:waitUntilDone:方法。
1.2 POSIX
Mac OS X 和 iOS 提供基于 C 语言支持的使用 POSIX 线程 API 来创建线程的方法。
1 void* PosixThreadMainRoutine(void* data) //这是C语言的普通函数
2 {
3 printf("PosixThreadMainRoutine\n");
4 return NULL;
5 }
6 -(void) createPOSIXThreads //这是Object-C类的成员方法
7 {
8 pthread_t posixThreadID;
9 int threadError = pthread_create(&posixThreadID, NULL, &PosixThreadMainRoutine, NULL);
10 }
1.3 NSObject
在 iOS 和 Mac OS X v10.5 及其之后,所有的对象都可能生成一个新的线程,并用它来执行它任意的方法。方法 performSelectorInBackground:withObject:新生成一个脱离的线程,使用指定的方法作为新线程的主体入口点。
比如,你可以使用当前对象创建一个新的线程:
1 -(void) myThreadMainMethod
2 {
3 printf("myThreadMainMethod\n");
4 }
5
6 -(void) createNSObjectThreads
7 {
8 [self performSelectorInBackground:@selector(myThreadMainMethod) withObject:nil];
9 }
调用该方法的效果和你在当前对象里面使用NSThread 的detachNewThreadSelector:toTarget:withObject:传递 selectore,object 作为参数的方法一样。新的线程将会被立即生成并运行,它使用默认的设置。
2 run loop
Run loop 是线程相关的的基础框架的一部分。一个 run loop 就是一个事件处理的循环,用来不停的调度工作以及处理输入事件。使用 run loop 的目的是让你的线程在有工作的时候忙于工作, 而没工作的时候处于休眠状态。Run loop相当是Linux系统中的信号处理程序,需要绑定感兴趣的信号。
Run loop 的管理并不完全自动的。你仍然需要设计你的线程代码在合适的时候启动 run loop 并正确响应输入事件。 Cocoa 和 Core Fundation 都自动在你应用程序的主线程启动一个 run loop objects 来帮助配置和管理你线程的 run loop。你的应用程序不需要显式的创建这些对象(run loop objects);每个线程,包括程序的主线程都有与之对应的 run loop object。 只有辅助线程才需要显式的运行它的 run loop。
2.1 剖析
Run loop是用来响应产生的事件,在代码中自己实现循环控制语句,来响应接收到的事件并调用处理程序。Run loop 接收输入事件来自两种不同的来源:
- 输入源(input source):从其它线程或应用传递来的异步事件。
- 定时源 (timer source):是一种同步事件,发生在特定时间或者重复的时间间隔。
如图 1所示是run loop与source之间的结构,run loop在接收到input source事件后,就会导致runUntilDate方法退出;而接收到timer source事件后,则不会退出。其中run loop除了能接收source事件外,还能产生notifications(消息),并可以指定observers来接收这些消息。
图 1
2.1.1 模式
run loop 有如下的几种模式,每种模式都是用来监听input source、timer source和notifications事件。每次在运行run loop时都需要为run loop指定某种模式:
2.1.2 第一个程序:定时源
如下是一个简单的定时器功能,其中在0.1秒后将触发响应方法doFireTimer 。
1 -(void) doFireTimer //定时器触发方法
2 {
3 printf("doFireTimer\n");
4 }
5
6 -(void) myThreadMainMethod //线程的入口函数
7 {
8 printf("myThreadMainMethod\n");
9
10 NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop]; //创建一个run loop对象
11 NSDate* futureDate = [NSDate dateWithTimeIntervalSinceNow:0.1];//设置run loop持续运行的时间
12 NSTimer* myTimer = [[NSTimer alloc] initWithFireDate:futureDate //创建一个定时器对象
13 interval:0.1
14 target:self
15 selector:@selector(doFireTimer)
16 userInfo:nil repeats:YES];
17 [myRunLoop addTimer:myTimer forMode:NSDefaultRunLoopMode]; //将定时器对象添加到run loop对象中。
18 [myRunLoop runUntilDate:futureDate]; //启动run loop对象。
19 }
2.2 使用
2.2.1 获得
为了获得当前线程的 run loop,你可以采用以下任一方式:
1) 使用 NSRunLoop 的 currentRunLoop 类方法来返回一个NSRunLoop 对象;
2) 使用CFRunLoopGetCurrent函数返回一个CFRunLoopRef对象。
如:
1 NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop]; //方式1
2 CFRunLoopRef runLoop = CFRunLoopGetCurrent(); //方式2
CFRunLoopRef 是在 CoreFoundation 框架内的,它提供了纯 C 函数的 API,所有这些 API 都是线程安全的。NSRunLoop 是基于 CFRunLoopRef 的封装,提供了面向对象的 API,但是这些 API 不是线程安全的。NSRunLoop 类定义了一个 getCFRunLoop 方法,该方法返回 一个可以传递给 Core Foundation 例程的 CFRunLoopRef 类型。因为两者都指向同一个run loop。
2.2.2 启动
run loop有三种启动方式,不同的启动方式调用不同的方法,包括以下这些:
表 3
方式 |
成员函数 |
描述 |
无条件 |
(void)run |
最简单的方法,但也最不推荐使用的,可以添加或删除输入源和定时器,但是退出 run loop 的唯一方法是杀死它。没有任何办法可以让这 run loop 运行在自定义模式下。 |
有限时间 |
(void)runUntilDate:(NSDate *)limitDate |
这种方式一直运行直到到某一事件到达或者规定的时间已经到期。如果是事件到达消息会被传递给相应的处理程序来处理,然后run loop 退出。你可以重新启动 run loop 来等待下一事件。如果是规定时间到期了,你只需简单的重启 run loop 或使用此段时间来做任何的其他工作。 |
特定模式 |
(BOOL)runMode:(NSString *)mode beforeDate:(NSDate *)limitDate |
这种方式是前两种方式的结合体。 |
2.2.3 退出
有两种方法可以让 run loop 处理事件之前退出:
1) 给 run loop 设置超时时间
2) 通知 run loop 停止
2.2.4 时机
仅当在为你的程序创建辅助线程的时候,你才需要显式运行一个 run loop。如果你使用 xcode提供的模板创建的程序,那么永远不需要自己显式的调用这些例程。Run loop 在要和线程有更多的交互时才需要,比如以下情况:
- 使用端口或自定义输入源来和其他线程通信
- 使用线程的定时器
- Cocoa中使用任何performSelector...的方法
- 使线程周期性工作
2.3 配置
在你在辅助线程运行 run loop 之前,你必须至少添加一输入源或定时器给它。 如果 run loop 没有任何源需要监视的话,它会在你启动之际立马退出。
2.3.1 定时源
为了给Run Loop配置一个定时源,只需创建一个定时器(NSTimer)对象并把它添加到NSRunLoop对象中。 其中定时源也有指针类型:CFRunLoopTimerRef,该类型是配合run loop的指针类型CFRunLoopRef使用的。并且将NSTimer 对象添加到NSRunLoop对象中有两种方式:自动和手动:
1) 自动
这种方式是通过调用NSTimer 的静态方法scheduledTimerWithTimeInterval,从而自动将创建的NSTimer 对象添加到run loop中。
2) 手动
这种方式是手动创建NSTimer 对象,然后调用NSRunLoop对象的addTimer方法将其添加进入run loop中。
如:
1 NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop];
2 NSDate* futureDate = [NSDate dateWithTimeIntervalSinceNow:1.0];
3
4 //自动方式,自动将NSTimer 对象添加到myRunLoop 中。
5 [NSTimer scheduledTimerWithTimeInterval:0.2
6 target:self
7 selector:@selector(myDoFireTimer1:) //这里的myDoFireTimer1方法是当时间到了后,响应的成员方法。
8 userInfo:nil
9 repeats:YES];
10
11 //手动方式,需要手动调用addTimer方法将myTimer添加到myRunLoop 中
12 NSTimer* myTimer = [[NSTimer alloc] initWithFireDate:futureDate
13 interval:0.1
14 target:self
15 selector:@selector(myDoFireTimer2:)
16 userInfo:nil
17 repeats:YES];
18 [myRunLoop addTimer:myTimer forMode:NSDefaultRunLoopMode];
2.3.2 观察者
除了安装源,你也可以添加 run loop 观察者来监视 run loop 的不同执行阶段情况。为了给 run loop 添加一个观察者,你可以创建 CFRunLoopObserverRef 不透明类型,并使用 CFRunLoopAddObserver 将它添加到你的 run loop。Run loop 观察者必须由 Core foundation 函数创建,即使是 Cocoa 程序。
1 -(void) myThreadMainMethod
2 {
3 printf("myThreadMainMethod\n");
4
5 NSRunLoop* myRunLoop = [NSRunLoop currentRunLoop];
6 CFRunLoopObserverContext context = {0, (__bridge void *)(self), NULL, NULL, NULL};
7 CFRunLoopObserverRef observer = CFRunLoopObserverCreate(kCFAllocatorDefault,kCFRunLoopAllActivities, YES, 0, &myRunLoopObserver, &context);
8 if (observer) { CFRunLoopRef cfLoop = [myRunLoop getCFRunLoop]; CFRunLoopAddObserver(cfLoop, observer, kCFRunLoopDefaultMode); }
9
10 NSDate* futureDate = [NSDate dateWithTimeIntervalSinceNow:0.1];
11 NSTimer* myTimer = [[NSTimer alloc] initWithFireDate:futureDate
12 interval:0.1
13 target:self
14 selector:@selector(doFireTimer)
15 userInfo:nil repeats:YES]; [myRunLoop addTimer:myTimer forMode:NSDefaultRunLoopMode];
16 [myRunLoop runUntilDate:futureDate];
17 }
2.3.2 输入源
对于Apple提供的guide中有关自定义输入源和port输入源真心看不懂,为了内容的完整性,所以将此部分添加在此,若有谁清楚这块内容的,希望能介绍介绍。
3 参考文献
[1] Threading Programming Guide.
iOS 并行编程:Thread的更多相关文章
- iOS 并行编程:NSOperation Queues
1 简介 1.1 功能 Operation Queue也是IOS的一种并行编程技术,类似Dispatch Queue可以帮助用户管理多线程.但是Operation Queue将任务封装在 ...
- iOS 并行编程:GCD Dispatch Queues
1 简介 1.1 功能 Grand Central Dispatch(GCD)技术让任务并行排队执行,根据可用的处理资源,安排他们在任何可用的处理器核心上执行任务.任务可以是一个函数 ...
- iOS 并行编程:GCD Dispatch Sources
1 简介 dispatch source是一种用于处理事件的数据类型,这些被处理的事件为操作系统中的底层级别.Grand Central Dispatch(GCD)支持如下的dispatch sour ...
- Task C# 多线程和异步模型 TPL模型 【C#】43. TPL基础——Task初步 22 C# 第十八章 TPL 并行编程 TPL 和传统 .NET 异步编程一 Task.Delay() 和 Thread.Sleep() 区别
Task C# 多线程和异步模型 TPL模型 Task,异步,多线程简单总结 1,如何把一个异步封装为Task异步 Task.Factory.FromAsync 对老的一些异步模型封装为Task ...
- iOS多线程编程原理及实践
摘要:iOS开发中,开发者不仅要做好iOS的内存管理,而且如果你的iOS涉及多线程,那你也必须了解iOS编程中对多线程的限制,iOS主线程的堆栈大小为1M,其它线程均为512KB,且这个限制开发者是无 ...
- Objective-C编程 — 并行编程
多线程 线程的基本概念 线程 (thread)是进程(process)A 内假想的持有 CPU 使用权的执行单位.一般情况下,一个进程 只有一个线程,但也可以创建多个线程并在进程中并行执行.应用在执行 ...
- Parallel并行编程初步
Parallel并行编程可以让我们使用极致的使用CPU.并行编程与多线程编程不同,多线程编程无论怎样开启线程,也是在同一个CPU上切换时间片.而并行编程则是多CPU核心同时工作.耗时的CPU计算操作选 ...
- .Net中的并行编程-2.ConcurrentStack的实现与分析
在上篇文章<.net中的并行编程-1.基础知识>中列出了在.net进行多核或并行编程中需要的基础知识,今天就来分析在基础知识树中一个比较简单常用的并发数据结构--.net类库中无锁栈的实现 ...
- C#~异步编程再续~大叔所理解的并行编程(Task&Parallel)
返回目录 并行这个概念出自.net4.5,它被封装在System.Threading.Tasks命名空间里,主要提供一些线程,异步的方法,或者说它是对之前Thread进行的二次封装,为的是让开发人员更 ...
随机推荐
- DataContractJsonSerializer类
DataContractJsonSerializer类 DataContractJsonSerializer类同样是提供JSON序列化的类.而且貌似有几个方法还和XML有点点关系. 注意用此类要引用S ...
- 使用Bugfree不应有的坏习惯
Bugfree是一款优秀的bug管理和追踪工具,因此受到不少公司的青睐.但实际的工作中,我发现不少开发或是测试的同事有一些不好的使用习惯,使得我们对Bugfree的利用不够高效.我下面列出使用Bugf ...
- 使用Arcglobe 10与3dmax建立三维城市
转自:http://www.cnblogs.com/jinlun/p/3380307.html 随着国家大力推进数字城市的建设,三维城市的建设也是势在必行的.与传统二维地图相比,三维城市在立体层次.视 ...
- fcitx中文输入法
Ubuntu自带的输入法不太尽如人意思,用起来也不方便,我在Ubuntu和FC中都是用Fcitx,很好用! 安装配置如下: 1. 安装 fcitx sudo apt-get install fcitx ...
- selenium1.0和selenium2.0页面等待处理详解
一.selenium1.0页面等待 1.……AndWait 经常会看到, selenium action命令中很多有这种……AndWait后缀, 例如click和clickAndWait命令: cli ...
- ModelSim仿真
(1)出现“Fatal: SDF files require Altera primitive library” 书上的方法是在ModelSim-SE下的使用,而我用的是ModelSim-Alter ...
- java操作pdf添加页眉条码添加水印图片
添加条码页眉以及图片水印 1. 引入jar包 1. itext-4.2.1.jar 2. itext-asian-5.2.0.jar 3. jbarcode-0.2.8.jar ...
- Spark在集群中的安装
今天由于所以要安装spark做一些实验.我已有的环境是: 操作系统:CentOS6.5 hadoop:hadoop2.4.1 JDK:1.7 集群环境:四个节点 闲话不说,以下是我的安装步骤: 说 ...
- PAT 1026
1026. Table Tennis (30) 时间限制 400 ms 内存限制 32000 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue A table ...
- libmad和libmpg123解码mp3在安卓手机上的比较
libmad和libmpg123解码mp3在安卓手机上的比较1. libmad 选自 http://sourceforge.net/projects/mad libmad-0.15.1b.tar.g ...