iOS Swift - 关于低功耗蓝牙管理器中信号量和排序的问题

iOS Swift - Question about semaphores and sequencing in Bluetooth Low Energy Manager

我以开源 Bluefruit 代码为例,特别是 BleManager class,它是与 CBCentralManager 的接口。我已经给作者发了邮件,他们没有回复:

Bluefruit BleManager class

看起来 class 是在单例架构中设计的(第 23 行的“共享”),因此在代码中的其他地方调用第一个“BleManager.connect() 时懒惰地构造.

让我感到困惑的是在 init() 中,有一个信号量“等待”函数:

override init() {
    super.init()

    centralManagerPoweredOnSemaphore.wait()
    centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.global(qos: .background), options: [:])
//        centralManager = CBCentralManager(delegate: self, queue: DispatchQueue.main, options: [:])
    }

我真的只习惯于 DispatchQueue.async() 线程中的信号量。这个 wait() 函数不是在主线程上调用的吗?这样不会封号吗?将取消阻止 .wait() 调用的 .signal() 调用位于第 289 行:

extension BleManager: CBCentralManagerDelegate {
    func centralManagerDidUpdateState(_ central: CBCentralManager) {

        DLog("centralManagerDidUpdateState: \(central.state.rawValue)")
        // Unlock state lock if we have a known state
        if central.state == .poweredOn || central.state == .poweredOff || central.state == .unsupported || central.state == .unauthorized {
            centralManagerPoweredOnSemaphore.signal()
        }

因此,一旦系统 centralManager 更新了 BLE 实用程序状态,就会调用它,只要它不是未知的,就会调用 .signal() 并且 init() 的其余部分将 运行 .我已经使用 print 语句来确认它是如何工作的。 centralManagerPoweredOnSemaphore.wait() 被调用,然后是 centralManagerDidUpdateState(),然后是 init() 的其余部分。不过我还是不明白:

虽然最后它起作用了,但我只是想知道事情的确切顺序实际上是如何 运行 使它正确地 运行 的。

他们正在使用信号量来阻止对 BleManager 对象的任何操作,直到中央退出 .unknown 状态。

创建的信号量初始值为 1。init 中的 wait 会将其递减为 0,并且不会阻塞。然后初始化中央,并在某个时候进入通电状态。此时signal将return信号量设为1.

现在看看其他函数,例如 connect 函数(第 167 行),您会看到它们首先做的是 wait,然后是 signal 信号量。考虑在两种不同状态下会发生什么:

  1. 中央尚未处于 .poweredOn 状态 - 信号量计数为 0,因此 wait 块。假设 BLE 状态在某个时候变为 .poweredOnwait 将结束,信号量立即释放,然后 connect 函数继续。
  2. central已经处于.poweredOn状态——信号量计数为1,所以wait不阻塞,然后立即释放信号量,connect函数继续.

其他函数的工作方式类似。

这种方法的优点是调用代码不需要一直检查状态;它可以访问 sharedInstance 然后立即调用 startScan 而无需检查 Central 是否已开机。