dispatch_semaphore 会形成优先级反转,慎用!

1、结论:慎用 dispatch_semaphore 作线程同步

与 OSSpinlock相似,使用 dispatch_semaphore 容易形成优先级反转:html

  • 此 API 没有记录当前持有信号量的线程,因此有高优先级的线程在等待锁时,内核没法知道该提升哪一个线程的调试优先级(QoS)markdown

  • 若是锁持有者优先级比其余线程低,高优先级的等待线程将一直等待app

高效率的线程同步有两个关键点:异步

  • 不忙等
  • 记录持有者

自旋锁是两点都不符合,dispatch_semaphore 是只符合不忙等。async

2、原理说明

下面先介绍一下 iOS 平台上的 QoS 概念和优先级反转避免机制,最后再说明为何 dispatch_semaphore 不能避免优先级反转。ide

1. QoS 传递

QoS(Quality of Service),用来指示某任务或队列的运行优先级。oop

  • iOS 系统主要使用如下两种机制来在不一样线程(或 queue)间传递 QoS:ui

    • 机制1:dispatch_asyncspa

    • 机制2:基于 XPC 的进程间通讯(IPC)线程

  • 系统的 QoS 传递规则比较复杂,主要参考如下信息:

    • 当前线程的 QoS

    • 若是是使用 dispatch_block_create() 方法生成的 dispatch_block,则考虑生成 block 时所调用的参数

    • dispatch_async 或 IPC 的目标 queue 或线程的 QoS

    调度程序会根据这些信息决定 block 以什么优先级运行。具体用法请参见QoS使用官方文档

若是没有其余线程同步地等待此 block,则 block 就按上面所说的优先级来运行。

若是出现了线程间同步等待的状况,则调度程序会根据状况调整线程的运行优先级。

2. 优先级反转及避免

  • 优先级反转:当前线程在同步地等待某个线程(线程1)完成某项操做,而当前线程的优先级比线程1的优先级高。

  • 优先级反转避免机制(Priority inversion avoidance):若是当前线程因等待某线程(线程1)上正在进行的操做(如 block1)而受阻,而系统知道 block1 所在的目标线程(owner),系统会经过提升相关线程的优先级来解决优先级反转的问题。

    • 若是系统不知道 block1 所在目标线程,则没法知道应该提升谁的优先级,也就没法解决反转问题

    • 记录了持有者信息(owner)的系统 API 以下:

      • pthread mutex、os_unfair_lock、以及基于这两者实现的其余上层 API

        • dispatch_once 的实现是基于 os_unfair_lock 的

        • NSLock、NSRecursiveLock、@synchronized 等的实现是基于 pthread mutex 的

      • dispatch_sync()

      • xpc_connection_send_with_message_sync()

      使用以上这些 API 可以在发生优先级反转时使系统启用优先级反转避免机制。

3. dispatch_semaphroe 不能避免优先级反转的缘由

  • semaphore 不是一个异步方法,因此它没有 QoS 的概念

  • 在调用 dispatch_semaphore_wait() 时,系统不知道哪一个线程会调用 dispatch_semaphore_signal() 方法,因此系统没法知道 owner 信息

dispatch_group 跟 semaphore 相似,在调用 enter() 方法时,没法预知谁会调用 leave(),因此系统也没法知道其 owner 是谁

参考资料

相关文章
相关标签/搜索