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进行的二次封装,为的是让开发人员更 ...
随机推荐
- Eclipse问题解决方案,不断更新
执行“software update”时出现:Error retrieving "feature.xml"... 执行“software update”时出现:Error retr ...
- 修改UISearchBar的Cancel按钮为中文等本地化问题
正确方法: 1:创建本地化strings. InfoPlist.strings 2:对InfoPlist.strings添加本地化语言. 即可. 只要添加文件, 系统会根据语言来调整显示文字 常见的搜 ...
- 【转】Android 学习笔记——利用JNI技术在Android中调用、调试C++代码
原文网址:http://cherishlc.iteye.com/blog/1756762 在Android中调用C++其实就是在Java中调用C++代码,只是在windows下编译生成DLL,在And ...
- 惊人事实 z
- Dispatcher及线程操作
WPF 应用程序启动后,会有两个线程: 1. 一个是用来处理UI呈现(处理UI的请求,比如输入和展现等操作). 2. 一个用来管理 UI的 (对UI元素及整个UI进行管理). WPF在线程里面是不可以 ...
- 【转】git使用教程
Git使用教程 一:Git是什么? Git是目前世界上最先进的分布式版本控制系统. 二:SVN与Git的最主要的区别? SVN是集中式版本控制系统,版本库是集中放在中央服务器的,而干活的时候,用的都是 ...
- Linux入门2
请设置系统时间和硬件时间保持一致:# hwclock --hctosys sed用法: 1.删除/etc/grub.conf文件中行首的空白符:sed -r 's@^[[:space:]]+@@g' ...
- 【JS】Intermediate7:jQuery:DOM API
1.jQuery also makes performing actions on many elements at the same time simple 2.eg:$('.note').css( ...
- 【Java基础】基础概念
Java 关键字 被Java语言赋予特定含义的单词 组成关键字的字母全部小写 goto和const作为保留字存在,目前并不使用 一般关键字在IDE中会高亮 用于定义数据类型的关键字 class i ...
- 一分钟快速入门openstack
一.它是什么,能干什么想认识一个事物,必须先弄明白它是什么,能干什么.首先说一下,openstack是一个搭建云平台的一个解决方案,说他不是个软件,但是我觉得说是一个软件,能够让大家认识更清晰些.op ...