多线程是一个比较轻量级的方法来实现单个应用程序内多个代码执行路径。
从技术角度来看,一个线程就是一个需要管理执行代码的内核级和应用级数据结 构组合。内核级结构协助调度线程事件,并抢占式调度一个线程到可用的内核之上。 应用级结构包括用于存储函数调用的调用堆栈和应用程序需要管理和操作线程属性 和状态的结构。
2.在应用程序中存 在多个线程提供了两个非常重要的的潜在优势:
多个线程可以提高应用程序的感知响应。
多个线程可以提高应用程序在多核系统上的实时性能。
多线程的弊端
(1) 当然多线程并不是解决程序性能问题的灵丹妙药。多线程带来好处同时也伴随着 潜在问题。应用程序内拥有多个可执行路径,会给你的代码增加更多的复杂性。每个 线程需要和其他线程协调其行为,以防止它破坏应用程序的状态信息。因为应用程序 内的多个线程共享内存空间,它们访问相同的数据结构。如果两个线程试图同时处理 相同的数据结构,一个线程有可能覆盖另外线程的改动导致破坏该数据结构。即使有 适当的保护,你仍然要注意由于编译器的优化导致给你代码产生很微妙的(和不那么 微妙)的 Bug。
(2)你需要考虑的另一个因素是你是否真的需要多线程或并发。多线程解决了如何在
同一个进程内并发的执行多路代码路径的问题。然而在很多情况下你是无法保证你所 在做的工作是并发的。多线程引入带来大量的开销,包括内存消耗和 CPU 占用。你会 发现这些开销对于你的工作而言实在太大,或者有其他方法会更容易实现
线程编程的危害之一是在多个线程之间的资源争夺。如果多个线程在同一个时间 试图使用或者修改同一个资源,就会出现问题。缓解该问题的方法之一是消除共享资 源,并确保每个线程都有在它操作的资源上面的独特设置。
3.线程 进程 任务的区别?
线程(线程)用于指代独立执行的代码段。
进程(process)用于指代一个正在运行的可执行程序,它可以包含多个线程。
任务(task)用于指代抽象的概念,表示需要执行工作。
4.线程包
虽然多线程的底层实现机制是 Mach 的线程,你很少(即使有)使用 Mach 级的线 程。相反,你会经常使用到更多易用的 POSIX 的 API 或者它的衍生工具。Mach 的实 现没有提供多线程的基本特征,但是包括抢占式的执行模型和调度线程的能力,所以 它们是相互独立的。
5.Run Loops
一个 run loop 是用来在线程上管理事件异步到达的基础设施。一个 run loop 为 线程监测一个或多个事件源。当事件到达的时候,系统唤醒线程并调度事件到 run loop,然后分配给指定程序。如果没有事件出现和准备处理,run loop 把线程置于休 眠状态。
你创建线程的时候不需要使用一个 run loop,但是如果你这么做的话可以给用户 带来更好的体验。Run Loops 可以让你使用最小的资源来创建长时间运行线程。因为 run loop 在没有任何事件处理的时候会把它的线程置于休眠状态,它消除了消耗 CPU 周期轮询,并防止处理器本身进入休眠状态并节省电源。 为了配置 run loop,你所需要做的是启动你的线程,获取 run loop 的对象引用, 设置你的事件处理程序,并告诉 run loop 运行。
6.解决多线程共享内存资源对同一资源的改变的冲突
线程编程的危害之一是在多个线程之间的资源争夺。如果多个线程在同一个时间 试图使用或者修改同一个资源,就会出现问题。缓解该问题的方法之一是消除共享资 源,并确保每个线程都有在它操作的资源上面的独特设置。因为保持完全独立的资源 是不可行的,所以你可能必须使用锁,条件,原子操作和其他技术来同步资源的访问。
(1)锁:锁提供了一次只有一个线程可以执行代码的有效保护形式。最普遍的一种锁是互斥排他锁,也就是我们通常所说的“mutex”。当一个线程试图获取一个当前已经被其 他线程占据的互斥锁的时候,它就会被阻塞直到其他线程释放该互斥锁。系统的几个 框架提供了对互斥锁的支持,虽然它们都是基于相同的底层技术。此外 Cocoa 提供了 几个互斥锁的变种来支持不同的行为类型,比如递归。
(2)条件:确保在你的应用程序任务执行的适当顺序。一个条 件作为一个看门人,阻塞给定的线程,直到它代表的条件变为真。当发生这种情况的 时候,条件释放该线程并允许它继续执行。POSIX 级别和基础框架都直接提供了条件 的支持。(如果你使用操作对象,你可以配置你的操作对象之间的依赖关系的顺序确 定任务的执行顺序,这和条件提供的行为非常相似)。
(3)原子操作
尽管锁和条件在并发设计中使用非常普遍,原子操作也是另外一种保护和同步访 问数据的方法。原子操作在以下情况的时候提供了替代锁的轻量级的方法,其中你可 以执行标量数据类型的数学或逻辑运算。原子操作使用特殊的硬件设施来保证变量的 改变在其他线程可以访问之前完成。