iOS 线程2--互斥,锁,优先级 翻转

来源:互联网 发布:unity3d 自动寻路 编辑:程序博客网 时间:2024/05/17 05:04


目录

1、介绍
2、OS X和iOS中的并发编程
    2.1、Threads
   2.2、Grand Central Dispatch
   2.3、Operation Queues
   2.4、Run Loops
3、并发编程中面临的挑战
   3.1、资源共享
   3.2、互斥
   3.3、死锁
   3.4、饥饿
   3.5、优先级反转
4、小结

正文

1和2两部分内容请看上一篇文章

3、并发编程中面临的挑战

使用并发编程会带来许多陷进。尽管开发者做得足够到位了,还是难以观察并行执行中相互作用的多任务的不同状态。问题往往发生在一些不确定性(不可预见性)的地方,在调试相关并发代码时会感觉到很无助。

关于并发编程的不可预见性有一个非常典型的例子:在1995年,NASA(美国宇航局)发送了火星探测器,但是当探测器成功着陆的时候,任务嘎然而止,火星探测器莫名其妙的不停重启——在计算机领域内,遇到的这中现象被定为为优先级反转,也就是说低优先级的线程一直阻塞着高优先级的线程。稍后我们会看到更多相关介绍。通过该示例,可以告诉我们即使拥有丰富的资源和大量优秀工程师,但是也会遭遇使用并发编程带来的陷阱。

3.1、资源共享

并发编程中许多问题的根源就是在多线程中访问共享资源。资源可以是一个属性、一个对象,通用的内存、网络设备和文件等等。在多线程中任意共享的资源都有一个潜在的冲突,开发者必须防止相关冲突的发生。

为了演示冲突问题,我们来看一个关于资源的简单示例:利用一个整型值作为计数器。在程序运行过程中,有两个并行线程A和B,这两个线程都尝试着同时增加计数器的值。问题来了,通过C或OC写的代码(增加计数器的值)不仅仅是一条指令,而是包括好多指令——要想增加计数器的值,需要从内存中读取出当前值,然后再增加计数器的值,最后还需要就爱那个这个增加的值写回内存中。

我们可以试着想一下,如果两个线程同时做上面涉及到的操作,会发生什么问题。例如,线程A和B都从内存中读取出了计数器的值,假设为17,然后线程A将计数器的值加1,并将结果18写回到内存中。同时,线程B也将计数器的值加1,并将结果18写回到内存中。实际上,此时计数器的值已经被破坏掉了——因为计数器的值17被加1了两次,应该为19,但是内存中的值为18。

race-condition@2x

 

这个问题成为资源竞争,或者叫做race condition,在多线程里面访问一个共享的资源,如果没有一种机制来确保线程A结束访问一个共享资源之前,线程B就开始访问该共享资源,那么资源竞争的问题总是会发生。试想一下,如果如果程序在内存中访问的资源不是一个简单的整型,而是一个复杂的数据结构,可能会发生这样的现象:当第一个线程正在读写这个数据结构时,第二个线程也来读这个数据结构,那么获取到的数据可能是新旧参半。为了防止出现这样的问题,在多线程访问共享资源时,需要一种互斥的机制。

在实际的开发中,情况甚至要比上面介绍的复杂,因为现代CPU为了对代码运行达到最优化,对改变从内存中读写数据的顺序(乱序执行)。

3.2、互斥

互斥访问的意思就是同一时刻,只允许一个线程访问某个资源。为了保证这一点,每个希望访问共享资源的线程,首先需要获得一个共享资源的互斥锁,一旦某个线程对资源完成了读写操作,就释放掉这个互斥锁,这样别的线程就有机会访问该共享资源了。

locking@2x

除了确保互斥锁的访问,还需要解决代码无序执行所带来的问题。如果不能确保CPU访问内存的顺序跟编程时的代码指令一样,那么仅仅依靠互斥锁的访问是不够的。为了解决由CPU的优化策略引起的代码无序执行,需要引入内存屏障(memory barrier)。通过设置内存屏障,来确保无序执行时能够正确跨越设置的屏障。

当然,互斥锁的实现是需要自由的竞争条件。这实际上是非常重要的一个保证,并且需要在现代CPU上使用特殊的指令。更多关于原子操作(atomic operation),请阅读Daniel写的文章:底层并发技术

从语言层面来说,在Objective-C中将属性以atomic的形式来声明,就能支持互斥锁了。实际上,默认情况下,属性是atomic的。将一个属性声明为atomic表示每次访问该属性都会进行加锁和解锁操作。虽然最把稳的做法就是将所有的属性都声明为atomic,但是这也会付出一定的代价。

获取资源上的锁会引发一定的性能代价。获取和释放锁需要自由的竞争条件(race-condition free),这在多核系统中是很重要的。另外,在获取锁的时候,线程有时候需要等待——因为其它的线程已经获得了资源的锁。这种情况下,线程会进入休眠状态,当其它线程释放掉相关资源的锁时,休眠的线程会得到通知。其实所有这些相关操作都是非常昂贵且复杂的。

这有一些不同类型的锁。当没有竞争时,有些锁是很廉价的(cheap),但是在竞争情况下,性能就会打折扣。同等条件下,另外一些锁则比较昂贵(expensive),但是在竞争情况下,会表现更好(锁的竞争是这样产生的:当一个或者多个线程尝试获取一个已经被别的线程获取了的锁)。

在这里有一个东西需要进行权衡:获取和释放锁所带来的开销。开发者需要确保代码中有获取锁和释放锁的语句。同时,如果获取锁之后,要执行一大段代码,这将带来风险:其它线程可能因为资源的竞争而无法工作(需要释放掉相关的锁才行)。

我们经常能看到并行运行的代码,但实际上由于共享资源中配置了相关的锁,所以有时候只有一个线程是出于激活状态的。要想预测一下代码在多核上的调度情况,有时候也显得很重要。我们可以使用Instrument的CPU strategy view来检查是否有效的利用了CPU的可用核数,进而得出更好的想法,以此来优化代码。

3.3、死锁

互斥解决了资源竞争的问题,但同时这也引入了一个新的问题:死锁。当多个线程在相互等待着对方的结束时,就会发生死锁,这是程序可能会被卡住。

dead-lock@2x

看看下面的代码——交换两个变量的值:

<ol class="linenums" style="margin: 0px 0px 0px 40px; padding: 0px 0px 0px 27px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; line-height: 1.5em; font-family: inherit; list-style: none;"><li value="1" class="L0" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; text-align: left; line-height: 2em; list-style: decimal;"><span class="kwd" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 136);">void</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);"> swap</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">(</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">A</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">,</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);"> B</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">)</span></li><li class="L1" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: rgb(238, 238, 238); font-style: inherit; font-family: inherit; text-align: left; line-height: 2em; list-style: decimal;"><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">{</span></li><li class="L2" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; text-align: left; line-height: 2em; list-style: decimal;"><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">    </span><span class="kwd" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 136);">lock</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">(</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">lockA</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">);</span></li><li class="L3" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: rgb(238, 238, 238); font-style: inherit; font-family: inherit; text-align: left; line-height: 2em; list-style: decimal;"><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">    </span><span class="kwd" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 136);">lock</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">(</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">lockB</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">);</span></li><li class="L4" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; text-align: left; line-height: 2em; list-style: decimal;"><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">    </span><span class="kwd" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 136);">int</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);"> a </span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">=</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);"> A</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">;</span></li><li class="L5" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: rgb(238, 238, 238); font-style: inherit; font-family: inherit; text-align: left; line-height: 2em; list-style: decimal;"><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">    </span><span class="kwd" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 136);">int</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);"> b </span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">=</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);"> B</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">;</span></li><li class="L6" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; text-align: left; line-height: 2em; list-style: decimal;"><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">    A </span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">=</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);"> b</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">;</span></li><li class="L7" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: rgb(238, 238, 238); font-style: inherit; font-family: inherit; text-align: left; line-height: 2em; list-style: decimal;"><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">    B </span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">=</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);"> a</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">;</span></li><li class="L8" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; text-align: left; line-height: 2em; list-style: decimal;"><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">    unlock</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">(</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">lockB</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">);</span></li><li class="L9" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: rgb(238, 238, 238); font-style: inherit; font-family: inherit; text-align: left; line-height: 2em; list-style: decimal;"><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">    unlock</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">(</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">lockA</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">);</span></li><li class="L0" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; text-align: left; line-height: 2em; list-style: decimal;"><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">}</span></li></ol>

大多数时候,这能够正常运行。但是当两个线程同时调用上面这个方法呢——使用两个相反的值:

<ol class="linenums" style="margin: 0px 0px 0px 40px; padding: 0px 0px 0px 27px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; line-height: 1.5em; font-family: inherit; list-style: none;"><li value="1" class="L0" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; text-align: left; line-height: 2em; list-style: decimal;"><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">swap</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">(</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">X</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">,</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);"> Y</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">);</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);"> </span><span class="com" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(136, 0, 0);">// thread 1</span></li><li class="L1" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: rgb(238, 238, 238); font-style: inherit; font-family: inherit; text-align: left; line-height: 2em; list-style: decimal;"><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">swap</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">(</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);">Y</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">,</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);"> X</span><span class="pun" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(102, 102, 0);">);</span><span class="pln" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(0, 0, 0);"> </span><span class="com" style="margin: 0px; padding: 0px; border: 0px; outline: 0px; vertical-align: baseline; background-color: transparent; font-style: inherit; font-family: inherit; color: rgb(136, 0, 0);">// thread 2</span></li></ol>

此时程序可能会由于死锁而被终止。线程1获得了X的一个锁,线程2获得了Y的一个锁。 接着它们会同时等待另外一把锁,但是永远都不会获得。

记住:在线程之间共享更多的资源,会使用更多的锁,同时也会增加死锁的概率。这也是为什么我们需要尽量减少线程间资源共享,并确保共享的资源尽量简单的原因之一。建议阅读以下底层并发编程API中的doing things asynchronously

 

3.4、饥饿

当你认为已经足够了解并发编程面临的陷阱 时,拐角处又出现了新的问题。锁定的共享资源会引起读写问题。大多数情况下,限制资源一次只能有一个线程进行访问,这是非常浪费的,比如一个读取锁只允许读,而不对资源进行写操作,这种情况下,同时可能会有另外一个线程等着着获取一个写锁。

为了解决这个问题,更好的方法不是简单使用读/写锁,例如给定一个writer preference,或者使用read-copy-update算法。Daniel在底层并发技术文章中有相关介绍。

3.5、优先级反转

本节开头介绍了美国宇航局发射的火星探测器在火星上遇到的并发问题。现在我们就来看看为什么那个火星探测器会失败,以及为什么有时候我们的程序也会遇到相同的问题——该死的优先级反转。

优先级反转是指程序在运行时低优先级的任务阻塞了高优先级的任务,有效的反转了任务的优先级。由于GCD提供了后台运行队列(拥有不同的优先级),包括I/O队列,所以通过GCD我们可以很好的来了解一下优先级反转的可能性。

高优先级和低优先级的任务之间在共享一个资源时,就可能发生优先级反转。当低优先级的任务获得了共享资源的锁时,该任务应该迅速完成,并释放掉锁,然后让高优先级的任务在没有明显的延时下继续执行。然而当低优先级阻塞着高优先级期间(低优先级获得的时间又比较少),如果有一个中优先级的任务(该任务不需要那个共享资源),那么可能会抢占低优先级任务,而被执行——因为此时高优先级任务是被阻塞的,所以中优先级任务是目前所有可运行任务中优先级最高的。此时,中优先级任务就会阻塞着低优先级任务,导致低优先级任务不能释放掉锁,也就会引起高优先级任务一直在等待锁的释放。

priority-inversion@2x

在我们的实际代码中,可能不会像火星探测器那样,遇到优先级反转时,不同的重启。

解决这个问题的方法,通常就是不要使用不同的优先级——将高优先级的代码和低优先级的代码修改为相同的优先级。当使用GCD时,总是使用默认的优先级队列。如果使用不同的优先级,就可能会引发事故。

虽然有些文章上说,在不同的队列中使用不同的优先级,这听起来不错,但是这回增加并发编程的复杂度和不可预见性。如果编程中,在高优先级任务中突然没有理由的卡住了,可能你会想起本文,以及称为优先级反转的问题,甚至还会想起美国宇航局的工程师也遇到这样的问题。

4、小结

希望通过本文你能够了解到并发编程带来的复杂性和相关问题。并发编程中,看起来,无论是多么简单的API,由此产生的问题会变得非常的难以观测,并且要想调试这类问题,往往都是比较困难的。

另外,并发实际上是一个非常棒的功能——它充分利用了现代多核CPU的强大计算能力。在开发中,关键的一点就是尽量让并发模型简单,这样可以限制锁的数量。

我们建议采纳的安全模式是这样的:从主线程中提取出使用到的数据,并利用一个操作队列在后台处理相关的数据,然后将后台处理的结果反馈到主队列中。使用这种方式,开发者不需要自己负责任何的锁,这也就减少了犯错误的概率。

0 0