不管是mac os X还是IOS都支持多个层次的多线程编程。创建一个低层的线程是相对简单的但是不是很安全的,创建一个高层的线程比较复杂但是比较安全,省去了多线程的同步操作。但是不管什么情况,你必须有一个函数或者方法来作为创建线程的主入口以及必须用一个现有的线程活动来开始线程。下面为了使用线程技术具有更加一般性,展示基本的线程创建过程。
线程创建继承了一些默认的属性,这主要决定于你使用的技术是什么。
1.使用NSThread:用两种方法来创建一个线程
- 使用detachNewThreadSelector:toTarget:withObject:这个类方法来产生一个新的线程。
这种方法的支持所有的mac os X版本。使用范例为:
[NSThread detachNewThreadSelector:@selector(myThreadMainMethod:) toTarget:self withObject:nil];
注意myThreadMainMethod:为线程的入口方法地址,而withObject就是你想传给该线程的数据。调用该类方法之后,线程立即启动,灵活性较差。
- 创建一个NSThread对象,并且调用它的start方法。(注意,这种方法有一定的限制,即只能应用于iOS and Mac OS X v10.5 之后的系统)
该方法支持在开始运行线程之前,可以获取以及设定各种各样的线程属性。同样也可以在运行线程之后使用线程对象。最简单的初始化线程对象的方法为:使用initWithTarget:selector:object:方法 。与第一种方法类似,指定了线程的入口方法,线程的目标,以及传入参数,但是它不会立即运行线程。你要开始运行线程的话,需要显式调用start方法。具体的例子为:
NSThread* myThread = [[NSThread alloc] initWithTarget:self
selector:@selector(myThreadMainMethod:)
object:nil];
[myThread start]; // Actually create the thread
当你拥有一个NSThread对象,而且它正在运行时,你可以使用performSelector:onThread:withObject:waitUntilDone: 方法发送消息给该线程。线程中支持selectors是一种线程间通信的便利方法(遗憾的是这只是在iOS中支持)。
2.使用POSIX线程
MAC OS X和IOS提供了C支持,因此可以用POSIX的线程API来创建线程。 这种技术实际上可应用与任何一种应用(包括cocoa和Cocoa touch)。如果你编写的是多平台软件,这种方式对你来说更加方便。POSIX只需要调用pthread_create就足够来创建线程。下面的代码就是采用POSIX产生线程的实例:
#include <assert.h>
#include <pthread.h>
void* PosixThreadMainRoutine(void* data)
{
// Do some work here.
return NULL;
}
void LaunchThread()
{
// Create the thread using POSIX routines.
pthread_attr_t attr;
pthread_t posixThreadID;
int returnVal;
returnVal = pthread_attr_init(&attr);
assert(!returnVal);
returnVal = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
assert(!returnVal);
int threadError = pthread_create(&posixThreadID, &attr, &PosixThreadMainRoutine, NULL);
returnVal = pthread_attr_destroy(&attr);
assert(!returnVal);
if (threadError != 0)
{
// Report an error.
}
}
使用上面的代码只能开始运行一个线程,但是会立即退出。为了更好的理解线程,你可以增加一下代码到PosixThreadMainRoutine()函数中来做一些实际的工作。你也可以传递一些实际的数据作为pthread_create的最后一个实参。
3.使用NSOperation:
NSOperation类是一个抽象类,用来封装单任务的代码和数据。可以参考其英文解释:The NSOperation class is an abstract class you use to encapsulate the code and data associated with a single task.因为是抽象类,所以不能直接使用该类,而使用它的子类或者一些系统定义的子类(NSInvocationOperation 或者 NSBlockOperation)来完成实际的任务。
注意:使用NSOperation的子类对象只能执行任务一次,而且不能再次执行它。你可以将它添加到一个操作队列中执行操作,这可以用NSOperationQueue的实例来完成它。操作队列要么把他们作为第二个线程来直接执行它的操作,要么是间接使用 libdispatch库 (也可以认为是 Grand Central Dispatch,GCD).
使用NSOperationQueue:
NSOperationQueue类规定了NSOperation对象的执行过程。当NSOperation的子类对象加入到队列,该操作在它显式取消或者完成它的任务之前会一直处于队列中。操作队列总是先执行具有最高优先级(相对与其他准备就绪的操作)的操作。
注意:在IOS4及其之后,operation queues采用GCD来执行操作,而在之前,为非并行的操作独立地创建线程,而且从当前的线程中启动非并行操作。
NSOperationQueue是服从KVC和KVO模式。你可以观察应用中用来控制其他部分的属性。这些可观察的属性包括:
-
operations
- read-only property -
operationCount
- read-only property -
maxConcurrentOperationCount
- readable and writable property -
suspended
- readable and writable property -
name
- readable and writable property
具体的代码实例为:
//先定义NSInvocation对象,NSInvocation类是指将一个动作转化为对象
NSInvocation* deleteInvocation = [NSInvocation invocationWithMethodSignature:[self methodSignatureForSelector:@selector(deleteDataAtPath:)]];
[deleteInvocation setTarget:self];
[deleteInvocation setSelector:@selector(deleteDataAtPath:)];//给NSInvocation对象添加对应的动作
[deleteInvocation setArgument:&cachePath atIndex:2];
//用NSInvocation对象来初始化一个NSOperation的子类NSInvocationOperation对象
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithInvocation:invoction];
//初始化一个操作队列
NSOperationQueue* operationQueue=[[NSOperationQueue alloc] init];
//在操作队列中加入操作
[operationQueue addOperation:operation];
[operation release];