线程是在一个应用程序里同时并行执行多路代码的技术之一。尽管更先进的operation objects和GCD提供了更现代和有效的方法来实现并行,OSX和iOS依然提供了创建和管理线程的接口。

关于线程
线程是在应用程序内部实现多个执行路径的相对轻量级的方式。在系统层面,程序并排运行,系统根据其需求和其他程序的需求,为每个程序分配执行时间。但是,在每个程序中,存在一个或多个执行线程,这些线程可用于同时或以几乎同时的方式执行不同的任务。系统本身实际上管理着这些执行线程,调度它们在可用内核上运行,并根据需要抢先中断它们以允许其他线程运行。 技术角度来看,线程是管理代码执行所需的内核级和应用级数据结构的组合。内核级结构协调事件对线程的调度和线程在其中一个可用内核上的抢先调度。应用程序级结构包括用于存储函数调用的调用堆栈以及应用程序需要管理和操作线程的属性和状态的结构。
术语:线程thread,可执行代码的分离路径;进程process,正在执行的一个或多个线程,任务task,需要被执行的工作任务
线程的替代方案:
Opearsion objects(GCD的上层封装),GCD,idle-time notifications(基于 NSNotificationQueue),Asynchronous functions异步方法(由系统平台定义个系统方法),timers(基于runloop的timeer source),Separate processes分离进程(某些情况下可以把某些业务分离給其他进程去做)

关于线程支持
· 线程包
Cocoa threads,就是NSThread
POSIX threads, 基于C的POSIX实现,经典的线程实现
Multiprocessing Services,多进程服务,在老MAC OS上使用的一种基于C的实现,忽略

· RunLoop
用于管理线程上异步事件的基础设施。通过监视线程的一个活着多个事件source来工作。当事件到达时,系统唤醒线程并将事件分配给runloop, 然后runloop将其分配给指定的处理程序,如果没有事件或没有事件被处理,runloop休眠。
OSX和iOS上,每个NSThread都有自己的runloop对象,启动线程,获取此线程的runloop引用,安装事件处理程序(创建source/timer,observer,指定 modes),执行 runloop,即可开启此线程runloop。详情见 RunLoop 官方文档笔记

同步工具
如果多个线程同时访问或修改同一资源时,显然会出现问题。解决问题的方式是取消资源共享,并保证每个线程都有自己专用的资源集合。但显然这不太可能,于是引出了同步工具:Locks,Conditions,atomic oprations,等。
· 线程内通信
直接发消息,比如perform selector;全局变量,共享内存空间等;Condition(基于系统或POSIX等支持);runloop source(使用custom source可以接受线程的消息);ports和socks(ported based source from run loop);message queue(古老的技术,忽略);Cocoa distributed objects(开销庞大的技术,忽略)

设计贴士
避免显示创建线程。没线程就是好线程😂,使用GCD/opearion objects来管理线程更高效和现代。
让线程有原因的干活,没活干要sleep。所以很多人创建线程后调用runloop来做这件事。
避免共享的数据结构。多线程访问必然遇到的问题,能避免避免,不能避免加锁。
线程和用户界面的问题。主线成跑UI,子线程不能负责UI。当然部分绘制任务可以跑后台runloop。
注意线程退出时的行为。线程在退出时,分离的线程可能执行其他工作,导致修饰数据。
处理异常。线程有自己的调用栈。所以也要有自己的异常处理。
干净的终止线程。最好的方式是让线程在达到终止条件时自然退出。
类库的线程安全。对于类库开发者来说,要保证自己的类库是线程安全的。

线程管理
线程对程序和系统都有内存和性能的开销。每个线程需要在初始化内核内存和程序内存。线程的栈空间和每个线程的数据都存储在你的程序的内存空间里。大部分的这些结构都在创建线程时创建和初始化,由于需要与内核进行交互,这个过程可能会相对昂贵。
可以使用 NSthread 创建线程,可以使用POSIX Threads创建线程,可以使用 NSObject 的performSelectorInBackground:withObject:方法产生线程。可以设置线程的优先级Priority,

需要编写进入线程的原则,在需要创建线程的时候,不要忘记使用Autorelease Pool
来对内存引用计数控制。对于创建色线程,应该有自己的异常处理机制。如果线程需要使用runloop, 还需处理相关runloop的mode,source等

需要在适当的时机结束一个线程,一般是让线程在入口点退出。

RunLoop
参考 RunLoop 官方文档笔记

关于线程的同步 Synchronization

应用程序中存在多个线程会导致潜在的问题,这些问题可能会导致从多个执行线程安全访问资源。修改相同资源的两个线程可能会以非预期的方式相互干扰。例如,一个线程可能会覆盖另一个线程的更改,或者将应用程序置于未知且可能无效的状态。如果幸运的话,损坏的资源可能会导致明显的性能问题或崩溃,这些问题相对容易追踪和修复。然而,如果你不幸运,线程错误可能会导致微妙的程序错误,直到很久以后才会出现,某些错误可能需要对基础编码假设进行重大修改。

说到线程安全性,一个好的设计模式就是最好的保护。避免共享资源并尽量减少线程之间的交互使得线程不太可能互相干扰。然而,完全无干扰的设计并不总是可行的。在你的线程必须交互的情况下,你需要使用同步工具来确保当他们交互时,他们可以安全地执行。

可使用的线程同步工具有:Atomic Operations(原子化操作),Memory Barriers and Volatile Variables,Lock(互斥锁,递归锁,读写锁,Distributed lock,Spin lock,Double-checked lock等),Conditions(条件是另一种类型的信号量,它允许线程在特定条件为真时互相发信号。条件通常用于指示资源的可用性或确保任务按特定顺序执行。当一个线程测试一个条件时,它会阻塞,除非该条件已经成立。直到其他线程明确更改并发出信号,它才会被阻塞。条件和互斥锁之间的区别在于可能允许多个线程同时访问条件。这种状况更像是一个看门人,它根据某些特定的标准让不同的线程通过门,Cocoa有NSCondition对此提供支持),Perform Selector Routines(使用 perform Selector 方式同步线程)

线程同步有性能开销,保证了代码的正确性。

end