iOS 并行编程:Thread

摘要:
2)创建一个新的NSThread对象,并调用它的start方法。1-myThreadMainMethod2{3printf;4}56-testMethod7{8NSThread*myThread=[[NSThreadalloc]initWithTarget:self9selector:@selector10object:nil];11[myThreadstart];12}如果你拥有一个NSThread对象,它的线程当前真正运行,你可以给该线程发送消息的唯一方法是在你应用程序里面的任何对象使用performSelector:onThread:withObject:waitUntilDone:方法。其中runloop除了能接收source事件外,还能产生notifications(消息),并可以指定observers来接收这些消息。1-doFireTimer//定时器触发方法2{3printf;4}56-myThreadMainMethod//线程的入口函数7{8printf;910NSRunLoop*myRunLoop=[NSRunLoopcurrentRunLoop];//创建一个runloop对象11NSDate*futureDate=[NSDatedateWithTimeIntervalSinceNow:0.1];//设置runloop持续运行的时间12NSTimer*myTimer=[[NSTimeralloc]initWithFireDate:futureDate//创建一个定时器对象13interval:0.114target:self15selector:@selector16userInfo:nilrepeats:YES];17[myRunLoopaddTimer:myTimerforMode:NSDefaultRunLoopMode];//将定时器对象添加到runloop对象中。

1 创建线程

1.1 NSThread

使用 NSThread 来创建线程有两个可以使用的方法:

1) 使用 detachNewThreadSelector:toTarget:withObject:类方法来生成一个新的线程

2) 创建一个新的 NSThread 对象,并调用它的 start 方法。

这两种创建线程的技术都在你的应用程序里面新建了一个脱离的线程。 一个脱离的线程意味着当线程退出的时候线程的资源由系统自动回收。

1-(void)myThreadMainMethod
2{
3printf("myThreadMainMethod ");
4}
5
6-(void)testMethod
7{
8NSThread*myThread=[[NSThreadalloc]initWithTarget:self
9selector:@selector(myThreadMainMethod)
10object:nil];
11[myThreadstart];
12}

如果你拥有一个 NSThread 对象,它的线程当前真正运行,你可以给该线程发送消息的唯一方法是在你应用程序里面的任何对象使用performSelector:onThread:withObject:waitUntilDone:方法。

1.2 POSIX

Mac OS X 和 iOS 提供基于 C 语言支持的使用 POSIX 线程 API 来创建线程的方法。

1void*PosixThreadMainRoutine(void*data)//这是C语言的普通函数2{
3printf("PosixThreadMainRoutine ");
4returnNULL;
5}
6-(void)createPOSIXThreads//这是Object-C类的成员方法
7{
8pthread_tposixThreadID;
9intthreadError=pthread_create(&posixThreadID,NULL,&PosixThreadMainRoutine,NULL);
10}

1.3 NSObject

在 iOS 和 Mac OS X v10.5 及其之后,所有的对象都可能生成一个新的线程,并用它来执行它任意的方法。方法 performSelectorInBackground:withObject:新生成一个脱离的线程,使用指定的方法作为新线程的主体入口点。

比如,你可以使用当前对象创建一个新的线程:

1-(void)myThreadMainMethod
2{
3printf("myThreadMainMethod ");
4}
5
6-(void)createNSObjectThreads
7{
8[selfperformSelectorInBackground:@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来接收这些消息。

iOS 并行编程:Thread第1张

图 1

2.1.1 模式

run loop 有如下的几种模式,每种模式都是用来监听input source、timer source和notifications事件。每次在运行run loop时都需要为run loop指定某种模式:

iOS 并行编程:Thread第2张

2.1.2 第一个程序:定时源

如下是一个简单的定时器功能,其中在0.1秒后将触发响应方法doFireTimer 。

1-(void)doFireTimer//定时器触发方法2{
3printf("doFireTimer ");
4}
5
6-(void)myThreadMainMethod//线程的入口函数7{
8printf("myThreadMainMethod ");
9
10NSRunLoop*myRunLoop=[NSRunLoopcurrentRunLoop];//创建一个runloop对象11NSDate*futureDate=[NSDatedateWithTimeIntervalSinceNow:0.1];//设置runloop持续运行的时间12NSTimer*myTimer=[[NSTimeralloc]initWithFireDate:futureDate//创建一个定时器对象13interval:0.1
14target:self
15selector:@selector(doFireTimer)
16userInfo:nilrepeats:YES];
17[myRunLoopaddTimer:myTimerforMode:NSDefaultRunLoopMode];//将定时器对象添加到runloop对象中。18[myRunLooprunUntilDate:futureDate];//启动runloop对象。19}

2.2 使用

2.2.1 获得

为了获得当前线程的 run loop,你可以采用以下任一方式:

1) 使用 NSRunLoop 的 currentRunLoop类方法来返回一个NSRunLoop 对象;

2) 使用CFRunLoopGetCurrent函数返回一个CFRunLoopRef对象。

如:

1NSRunLoop*myRunLoop=[NSRunLoopcurrentRunLoop];//方式12CFRunLoopRefrunLoop=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中。

如:

1NSRunLoop*myRunLoop=[NSRunLoopcurrentRunLoop];
2NSDate*futureDate=[NSDatedateWithTimeIntervalSinceNow:1.0];
3
4//自动方式,自动将NSTimer对象添加到myRunLoop中。5[NSTimerscheduledTimerWithTimeInterval:0.2
6target:self
7selector:@selector(myDoFireTimer1:)//这里的myDoFireTimer1方法是当时间到了后,响应的成员方法。8userInfo:nil
9repeats:YES];
10
11//手动方式,需要手动调用addTimer方法将myTimer添加到myRunLoop中12NSTimer*myTimer=[[NSTimeralloc]initWithFireDate:futureDate
13interval:0.1
14target:self
15selector:@selector(myDoFireTimer2:)
16userInfo:nil
17repeats:YES];
18[myRunLoopaddTimer:myTimerforMode:NSDefaultRunLoopMode];

2.3.2 观察者

除了安装源,你也可以添加 run loop 观察者来监视 run loop 的不同执行阶段情况。为了给 run loop 添加一个观察者,你可以创建 CFRunLoopObserverRef 不透明类型,并使用 CFRunLoopAddObserver 将它添加到你的 run loop。Run loop 观察者必须由 Core foundation 函数创建,即使是 Cocoa 程序。

1-(void)myThreadMainMethod
2{
3printf("myThreadMainMethod ");
4
5NSRunLoop*myRunLoop=[NSRunLoopcurrentRunLoop];
6CFRunLoopObserverContextcontext={0,(__bridgevoid*)(self),NULL,NULL,NULL};
7CFRunLoopObserverRefobserver=CFRunLoopObserverCreate(kCFAllocatorDefault,kCFRunLoopAllActivities,YES,0,&myRunLoopObserver,&context);
8if(observer){CFRunLoopRefcfLoop=[myRunLoopgetCFRunLoop];CFRunLoopAddObserver(cfLoop,observer,kCFRunLoopDefaultMode);}
9
10NSDate*futureDate=[NSDatedateWithTimeIntervalSinceNow:0.1];
11NSTimer*myTimer=[[NSTimeralloc]initWithFireDate:futureDate
12interval:0.1
13target:self
14selector:@selector(doFireTimer)
15userInfo:nilrepeats:YES];[myRunLoopaddTimer:myTimerforMode:NSDefaultRunLoopMode];
16[myRunLooprunUntilDate:futureDate];
17}

2.3.2 输入源

对于Apple提供的guide中有关自定义输入源和port输入源真心看不懂,为了内容的完整性,所以将此部分添加在此,若有谁清楚这块内容的,希望能介绍介绍。

3 参考文献

[1] Threading Programming Guide.

免责声明:文章转载自《iOS 并行编程:Thread》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇[转]走近 STLLinux程序编译链接动态库版本号的问题下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

使用多线程时,传递 request 对象丢失

1.原因描述 我们在工作中遇到耗时的一些操作时我们会使用多线程或者mq来解决以便提高程序的响应速度。但是使用多线程时遇到一个问题,我单独开一个线程去进行其他逻辑处理时,在发送消息之前(未开启多线程时)我们是可以获取到 request 信息的,但是在新开的线程中确是无法获取到 request 信息(request is  null)。 2.代码演示 主线程代...

.Net 调式案例—实验4 高CPU(High CPU)回顾

转载: https://www.cnblogs.com/softfair/archive/2008/03/03/dotnet-Debugging-Demos---Lab-4-HighCPU--Review.html   .Net 调式案例—实验4 高CPU(High CPU)回顾   现在开始第四个实验。 前面的案例和设置指导 请参看前面发布的文章。...

【转】 .NET中STAThread和MTAThread

ref:http://blog.csdn.net/dyllove98/article/details/9735955 1 COM中的公寓 本文讨论进程内COM组件。以一个示例直观演示STAThread和MTAThread的作用和区别。 1.1 基本规则 公寓是COM组件的运行环境,日常生活中公寓是用来住人的,COM中的公寓是用来住COM组件的对象的,每个...

在主线程中慎用WaitForSingleObject (WaitForMultipleObjects)

在主线程中慎用WaitForSingleObject (WaitForMultipleObjects) 下面的代码我调试了将近一个星期,你能够看出什么地方出了问题吗?线程函数: DWORD WINAPI ThreadProc(    while(!bTerminate)    {        // 从一个链表中读取信息并且插入到CListCtrl中...

C#基础--应用程序域(Appdomain)

AppDomain理解为了保证代码的键壮性CLR希望不同服务功能的代码之间相互隔离,这种隔离可以通过创建多个进程来实现,但操作系统中创建进程是即耗时又耗费资源的一件事,所以在CLR中引入了AppDomain的概念,AppDomain主要是用来实现同一进程中的各AppDomain之间的隔离,AppDomain可以用以下特征来描述它的全貌: AppDomai...

windows 最大支持线程数

WINDOWS操作系统中可以允许最大的线程数 默认情况下,一个线程的栈要预留1M的内存空间 而一个进程中可用的内存空间只有2G,所以理论上一个进程中最多可以开2048个线程 但是内存当然不可能完全拿来作线程的栈,所以实际数目要比这个值要小。 你也可以通过连接时修改默认栈大小,将其改的比较小,这样就可以多开一些线程。 如将默认栈的大小改成512K,这样理论...