ios 多线程

整理

http://www.dreamingwish.com/dream-2012/ios-multi-threaded-programming-guide-directory.html

http://www.cnblogs.com/likwo/archive/2011/11/01/2232309.html 待看

术语:

  1. 线程(线程)用于指代独立执行的代码段。
  2. 进程(process)用于指代一个正在运行的可执行程序,它可以包含多个线程。
  3. 任务(task)用于指代抽象的概念,表示需要执行工作。

一个线程是代码段和数据结构组合,同进程下线程共享相同的进程空间。

多线程:多核已经实现多任务,多线程可以更加有效率。单个应用程序内多个代码段执行,不同核、同内核不同时间段、同内存。

应用多线程的目的:解决了如何在同一个进程内并发的执行多路代码路径的问题。

应用多线程的负面:多线程之间的资源争夺,带来大量的开销,包括内存消耗和CPU占用。有时开销实在太大,其他更容易实现。

应用多线程出现的问题:1.如果多个线程在同一个时间试图使用或者修改同一个资源,就会出现问题。缓解该问题的方法之一是消除共享资源,并确保每个线程都有在它操作的资源上面的独特设置。因为保持完全独立的资源是不可行的,所以你可能必须使用锁,条件,原子操作和其他技术来同步资源的访问。锁提供了一次只有一个线程可以执行代码的有效保护形式。最普遍的一种锁是互斥排他锁,也就是我们通常所说的mutex。当一个线程试图获取一个当前已经被其他线程占据的互斥锁的时候,它就会被阻塞直到其他线程释放该互斥锁。系统的几个框架提供了对互斥锁的支持,虽然它们都是基于相同的底层技术。此外Cocoa提供了几个互斥锁的变种来支持不同的行为类型,比如递归。2.不同时间段,资源的修改。系统提供线程执行的条件,一个条件作为一个看门人,阻塞给定的线程,直到它代表的条件变为真。(如果你使用操作对象,你可以配置你的操作对象之间的依赖关系的顺序确定任务的执行顺序,这和条件提供的行为非常相似)

多线程技术:Cocoa threadsPOSIX threadsMultiprocessing Services

多线程的替代方法:Operation objectsGrand Central Dispatch (GCD)Idle-time notificationsAsynchronous functionsTimersSeparate processes


系统run loop组件。一个run loop是用来在线程上管理事件异步到达的基础设施。一个run loop为线程监测一个或多个事件源。当事件到达的时候,系统唤醒线程并调度事件到run loop,然后分配给指定程序。如果没有事件出现和准备处理,run loop把线程置于休眠状态。

为了配置run loop,你所需要做的是启动你的线程,获取run loop的对象引用,设置你的事件处理程序,并告诉run loop运行。CocoaCarbon提供的基础设施会自动为你的主线程配置相应的run loop。如果你打算创建长时间运行的辅助线程,那么你必须为你的线程配置相应的run loop


线程启动之后,线程就进入三个状态中的任何一个:运行(running)、就绪(ready)、阻塞(blocked)。如果一个线程当前没有运行,那么它不是处于阻塞,就是等待外部输入,或者已经准备就绪等待分配CPU。线程持续在这三个状态之间切换,直到它最终退出或者进入中断状态。


多线程会占用你应用程序(和系统的)的内存使用和性能方面的资源。每个线程都需要分配一定的内核内存和应用程序内存空间的内存。管理你的线程和协调其调度所需的核心数据结构存储在使用Wired Memory的内核里面。你线程的堆栈空间和每个线程的数据都被存储在你应用程序的内存空间里面。这些数据结构里面的大部分都是当你首次创建线程或者进程的时候被创建和初始化的,它们所需的代价成本很高,因为需要和内核交互。

量化了在你应用程序创建一个新的用户级线程所需的大致成本。这些成本里面的部分是可配置的,比如为辅助线程分配堆栈空间的大小。创建一个线程所需的时间成本是粗略估计的,仅用于当互相比较的时候。线程创建时间很大程度依赖于处理器的负载,计算速度,和可用的系统和程序空间。

Thread creation costs

Kernel data structuresApproximately 1 KB)、

Stack space512 KB (secondary threads)

8 MB (Mac OS X main thread)

1 MB (iOS main thread)

Creation timeApproximately 90 microseconds


一。创建一个线程

1    使用NSThread

使用NSThread来创建线程有两个可以的方法:脱离的线程退出的时候线程的资源由系统自动回收。

a.使用detachNewThreadSelector:toTarget:withObject:类方法来生成一个新的线程。只要简单的提供你想要使用为线程主体入口的方法的名称(被指定为一个selector),和任何你想在启动时传递给线程的数据。

[NSThread detachNewThreadSelector:@selector(myThreadMainMethod:) toTarget:self withObject:nil];


b.创建一个新的NSThread对象,并调用它的start方法。(仅在iOSMac OS X v10.5及其之后才支持)


NSThread* myThread = [[NSThread alloc] initWithTarget:self

                      selector:@selector(myThreadMainMethod:)

                                        object:nil];

[myThread start];  


2    使用POSIX的多线程

Mac OS XiOS提供基于C语言支持的使用POSIX线程API来创建线程的方法。该技术实际上可以被任何类型的应用程序使用(包括CocoaCocoa Touch的应用程序),并且如果你当前真为多平台开发应用的话,该技术可能更加方便。你使用来创建线程的POSIX例程被调用的时候,使用pthread_create刚好足够。


3    使用NSObject来生成一个线程,需要设置一个自动释放池(如果你没有使用垃圾回收机制),要使用它的时候配置线程的run loop

[myObj performSelectorInBackground:@selector(doSomething) withObject:nil];


4.其它


二。配置线程属性

配置线程的堆栈大小

配置线程本地存储

设置线程的脱离状态

 设置线程的优先级


三。线程的主体入口点

1    创建一个自动释放池(Autorelease Pool

2    设置异常处理

3    设置一个Run Loop

四。中断线程

CocoaPOSIXMultiprocessing Services提供了直接杀死线程的例程,但是推荐的方法是让它在它主体入口点正常退出。

杀死一个线程阻止了线程本身的清理工作。线程分配的内存可能造成泄露,并且其他线程当前使用的资源可能没有被正确清理干净,之后造成潜在的问题。



Run Loops

Run loops是线程相关的的基础框架的一部分。一个run loop就是一个事件处理的循环,用来不停的调度工作以及处理输入事件。使用run loop的目的是让你的线程在有工作的时候忙于工作,而没工作的时候处于休眠状态。

Run loop的管理并不完全自动的。你仍然需要设计你的线程代码在合适的时候启动run loop并正确响应输入事件。Cocoa和Core Fundation都提供了run loop objects来帮助配置和管理你线程的run loop。你的应用程序不需要显式的创建这些对象(run loop objects);每个线程,包括程序的主线程都有与之对应的run loop object。只有辅助线程才需要显式的运行它的run loop。在Carbon和Cocoa程序中,主线程会自动创建并运行它run loop,作为一般应用程序启动过程的一部分。

以下各部分提供更多关于run loops以及如何为你的应用程序配置它们。关于run loop object的额外信息,参阅NSRunLoop Class Reference和CFRunLoop Reference文档。



Run loop是一个循环,线程进入并使用它来运行响应输入事件的事件处理程序。你的代码要有while或for循环语句来驱动run loop。在循环中,使用run loop object来运行事件处理代码,它响应接收到的事件并启动已经安装的处理程序。

Run loop接收输入事件来自两种不同的来源:输入源(input source)和定时源(timer source)。输入源传递异步事件,通常消息来自于其他线程或程序。定时源则传递同步事件,发生在特定时间或者重复的时间间隔。两种源都使用程序的某一特定的处理例程来处理到达的事件。

除了处理输入源,run loops也会生成关于run loop行为的通知(notifications)。注册的run loop观察者(run-loop Observers)可以收到这些通知,并在线程上面使用它们来做额外的处理。你可以使用Core Foundation在你的线程注册run-loop观察者。

输入源异步的发送消息给你的线程。事件来源取决于输入源的种类:基于端口的输入源和自定义输入源。

定时源

定时源在预设的时间点同步方式传递消息。

Run Loop观察者

源是合适的同步或异步事件发生时触发,而run loop观察者则是在run loop本身运行的特定时候触发。你可以使用run loop观察者来为处理某一特定事件或是进入休眠的线程做准备。你可以将run loop观察者和以下事件关联:

  • Run loop入口
  • Run loop何时处理一个定时器
  • Run loop何时处理一个输入源
  • Run loop何时进入睡眠状态
  • Run loop何时被唤醒,但在唤醒之前要处理的事件
  • Run loop终止

每次运行run loop,你线程的run loop对会自动处理之前未处理的消息,并通知相关的观察者。具体的顺序如下:

  1. 通知观察者run loop已经启动
  2. 通知观察者任何即将要开始的定时器
  3. 通知观察者任何即将启动的非基于端口的源
  4. 启动任何准备好的非基于端口的源
  5. 如果基于端口的源准备好并处于等待状态,立即启动;并进入步骤9。
  6. 通知观察者线程进入休眠
  7. 将线程置于休眠直到任一下面的事件发生:
    • 某一事件到达基于端口的源
    • 定时器启动
    • Run loop设置的时间已经超时
    • run loop被显式唤醒
  8. 通知观察者线程将被唤醒。
  9. 处理未处理的事件
    • 如果用户定义的定时器启动,处理定时器事件并重启run loop。进入步骤2
    • 如果输入源启动,传递相应的消息
    • 如果run loop被显式唤醒而且时间还没超时,重启run loop。进入步骤2
  10. 通知观察者run loop结束。

因为定时器和输入源的观察者是在相应的事件发生之前传递消息,所以通知的时间和实际事件发生的时间之间可能存在误差。如果需要精确时间控制,你可以使用休眠和唤醒通知来帮助你校对实际发生事件的时间。

因为当你运行run loop时定时器和其它周期性事件经常需要被传递,撤销run loop也会终止消息传递。典型的例子就是鼠标路径追踪。因为你的代码直接获取到消息而不是经由程序传递,因此活跃的定时器不会开始直到鼠标追踪结束并将控制权交给程序。

线程同步
为了防止不同线程意外修改数据,你可以设计你的程序没有同步问题,或你也可以使用同步工具。
1 原子操作
2 内存屏障和 Volatile 变量
3 锁。当心死锁(Deadlocks)和活锁(Livelocks)
使用POSIX互斥锁、使用NSLock类、使用@synchronized指令、使用其他Cocoa锁、使用NSConditionLock对象、使用NSDistributedLock对象
4 条件 
使用NSCondition类、使用POSIX条件
5 执行Selector例程



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值