蜀道之难,难于上青天

0%

闲话iOS多线程

随着硬件的发展和多核 CPU 的普及,CPU 的性能越来越强了。为了让 CPU 充分运转,聪明的计算机科学家设计出了多线程模式,一个线程也就是相应的一条代码路径,多线程就是多条代码路径。

线程队列

那么怎么控制这些代码路径呢,于是就应运而生了一些代码路径的组合,叫做线程队列。这些队列有不同的执行代码路径的方式,比如窜行执行、并行执行等。

##窜行队列
可以把窜行队列当作并行队列的特殊情况,也就是最大并发数量为1。执行完了一个代码路径之后,根据优先级等因素,接着执行下一个,并不保证严格按照先进先出的顺序执行。那么问题来了,假如要控制窜行队列的执行顺序该怎么办呢,于是有了依赖这个概念,也就是一个代码路径依赖于另外一些代码路径,等到它依赖的路径都执行完了,这一个代码路径才能上路,那么这样就能严格控制执行顺序了。

并行队列

并行队列呢,也能通过依赖控制好某些路径的先后顺序,但是这个并行出现的问题就是要知道并发出去的代码路径都已经执行完毕,要做下一步工作了,于是并行队列就提供了这个功能。并行队列的应用场景可以是一些相互之间没有影响的工作。

取消队列执行

怎么让一个正在执行的代码路径停止呢,建议的做法是,要经常性的在关键性的点检查当前的状态,假如当前处于canceled状态,则停止执行下去,而且这个代码路径也没有机会再次执行了。让一个队列停止,这个队列也只是将当前的代码路径的状态置为canceled,也不发配新的代码路径执行了,恢复之后会继续分配。

既然是多线程,那么不可避免的会出现资源抢夺,于是锁出现了。有资源竞争的互斥锁,有适用于生产者消费者的条件锁,有适用于递归的递归锁。使用锁的过程中要时刻注意防止死锁的发生。把用于访问共享事物的代码块称为临界区。不能让一个临界区始终处于等待状态,也不能让一个临界区始终占有共享区间。

互斥锁

互斥锁,只能对临界区加锁一次,不能对同一个线程加多次锁,这样会造成死锁。对临界区加锁的时候,如果临界区被使用了,则当前线程被阻塞,直到临界区被释放,轮到当前线程进入临界区。假如有多个线程处于等待状态,则根据优先级进行队列处理。

条件锁

比互斥锁多的一个是只有锁在特定条件下才能加锁,释放锁的时候可以指定锁的当前条件。适用于生产者消费者模式,一个线程负责生产,其他线程负责消费。负责生产的轮询进入临界区,条件则是一个判定是否要生产的条件,比如货物数量为10则开始生产,生产完毕后将条件设置为shouldProduct = false,消费线程可以进入临界区消费。负责消费的线程出临界区的时候,根据剩余数量判断是否需要生产,如需生产,则将条件shouldProduct = true,则生产线程进入临界区生产。

递归锁

当在递归情况下,使用互斥锁的时候,会造成死锁。这种情况下适用递归锁,允许在一个线程里多次加锁和解锁,当解锁次数跟加锁次数相等时,出临界区,由于要做额外的加锁次数判断,开销会比互斥锁大。