使用 os_unfair_lock 替代 DispatchQueue?!

我们使用 os_unfair_lock 来替代 DispatchQueue 作为锁机制。注意,os_unfair_lock 是 iOS 10.0+ 和 macOS 10.12+ 可用的。

使用 os_unfair_lock 时需要注意,它必须被存储在适当的位置(例如,作为实例变量或静态变量),并且必须确保锁被正确初始化和使用。

另外,os_unfair_lock 是一个互斥锁,并且不像 DispatchQueue 那样可以用于异步任务。它只是用于同步代码的锁。

我们将创建一个线程安全的类,使用 os_unfair_lock 来保护对其内部数据的访问。

注意:os_unfair_lock 必须使用 OS_UNFAIR_LOCK_INITIALIZER 初始化,或者使用 init 方法(在 Swift 中,init() 会返回一个初始化的锁)。

由于 os_unfair_lock 是值类型(在 Swift 中是一个结构体),我们可以将其作为属性存储。

但是请注意,os_unfair_lock 必须使用 & 传递给系统函数,因此我们在锁定时需要将其声明为变量(即可变的)。

我们来看一个示例,如何使用 os_unfair_lock 来保护一个简单的计数器。

另外,需要注意,os_unfair_lock 不能递归使用,即同一个线程不能多次锁定,否则会导致死锁。

我们使用以下步骤:

  1. 声明一个 os_unfair_lock 属性,并初始化为 OS_UNFAIR_LOCK_INITIALIZER。

  2. 在需要加锁的代码块中,使用 os_unfair_lock_lock 和 os_unfair_lock_unlock。

但是,在 Swift 中,我们也可以使用 withLock 类似的模式来确保锁的获取和释放。

由于 os_unfair_lock 是低级锁,我们需要注意避免在锁定期间抛出错误,确保在退出时释放锁。

我们可以设计一个类似于 DispatchQueue.sync 的闭包执行方式,但是使用 os_unfair_lock。

以下详细解释如何用 os_unfair_lock 替代 DispatchQueue 实现线程同步

1. 基本用法对比

使用 DispatchQueue(之前的方式)

复制代码
class DataManager {
    private let queue = DispatchQueue(label: "com.example.datamanager", attributes: .concurrent)
    private var data: [String: Any] = [:]
    
    func setValue(_ value: Any, forKey key: String) {
        queue.async(flags: .barrier) {
            self.data[key] = value
        }
    }
    
    func getValue(forKey key: String) -> Any? {
        var result: Any?
        queue.sync {
            result = self.data[key]
        }
        return result
    }
}

使用 os_unfair_lock(优化后)

复制代码
import os.lock

class DataManager {
    private var lock = os_unfair_lock()
    private var data: [String: Any] = [:]
    
    func setValue(_ value: Any, forKey key: String) {
        os_unfair_lock_lock(&lock)
        defer { os_unfair_lock_unlock(&lock) }
        data[key] = value
    }
    
    func getValue(forKey key: String) -> Any? {
        os_unfair_lock_lock(&lock)
        defer { os_unfair_lock_unlock(&lock) }
        return data[key]
    }
}

2. 封装成易用的类型

复制代码
import os.lock

final class UnfairLock {
    private var _lock = os_unfair_lock()
    
    func lock() {
        os_unfair_lock_lock(&_lock)
    }
    
    func unlock() {
        os_unfair_lock_unlock(&_lock)
    }
    
    func tryLock() -> Bool {
        return os_unfair_lock_trylock(&_lock)
    }
    
    func withLock<T>(_ block: () throws -> T) rethrows -> T {
        lock()
        defer { unlock() }
        return try block()
    }
}

// 使用示例
class ThreadSafeContainer<T> {
    private let lock = UnfairLock()
    private var storage: [T] = []
    
    func append(_ element: T) {
        lock.withLock {
            storage.append(element)
        }
    }
    
    var count: Int {
        lock.withLock {
            storage.count
        }
    }
    
    func removeAll() {
        lock.withLock {
            storage.removeAll()
        }
    }
}

3. 处理复杂场景

读写锁(Read-Write Lock)

复制代码
final class ReadWriteLock {
    private var lock = os_unfair_lock()
    private var readers = 0
    
    func read<T>(_ block: () throws -> T) rethrows -> T {
        os_unfair_lock_lock(&lock)
        readers += 1
        if readers == 1 {
            // 第一个读者,这里可以设置写锁
        }
        os_unfair_lock_unlock(&lock)
        
        defer {
            os_unfair_lock_lock(&lock)
            readers -= 1
            if readers == 0 {
                // 最后一个读者,这里可以释放写锁
            }
            os_unfair_lock_unlock(&lock)
        }
        
        return try block()
    }
    
    func write<T>(_ block: () throws -> T) rethrows -> T {
        os_unfair_lock_lock(&lock)
        defer { os_unfair_lock_unlock(&lock) }
        return try block()
    }
}

4. 性能对比和注意事项

性能优势:

  • os_unfair_lockDispatchQueue 性能更高,尤其是在高频锁操作场景

  • 内存占用更小(仅 4 字节)

  • 没有线程优先级反转问题

重要注意事项:

  1. 不可递归锁

    // ❌ 错误:会导致死锁
    lock.withLock {
    lock.withLock { // 同一个线程再次加锁会死锁
    // ...
    }
    }

2.不可在锁内休眠

复制代码
// ❌ 错误:不要在锁内执行耗时操作
lock.withLock {
    Thread.sleep(forTimeInterval: 1)  // 可能导致性能问题
    // ...
}

3、Swift 5.7+ 的新 API

复制代码
// iOS 16+ / macOS 13+ 可以使用更安全的 API
import os.lock

@available(iOS 16.0, macOS 13.0, *)
class ModernLock {
    private let lock = OSAllocatedUnfairLock()
    
    func updateData() {
        lock.withLock {
            // 线程安全操作
        }
    }
}

5. 完整示例

复制代码
import os.lock

class ThreadSafeCache<Key: Hashable, Value> {
    private struct WrappedLock {
        var lock = os_unfair_lock()
    }
    
    private var locks: [WrappedLock]
    private var storage: [Key: Value]
    
    init(capacity: Int = 16) {
        storage = [:]
        locks = (0..<capacity).map { _ in WrappedLock() }
    }
    
    private func lockIndex(for key: Key) -> Int {
        return abs(key.hashValue) % locks.count
    }
    
    func set(_ value: Value, for key: Key) {
        let index = lockIndex(for: key)
        os_unfair_lock_lock(&locks[index].lock)
        defer { os_unfair_lock_unlock(&locks[index].lock) }
        storage[key] = value
    }
    
    func get(_ key: Key) -> Value? {
        let index = lockIndex(for: key)
        os_unfair_lock_lock(&locks[index].lock)
        defer { os_unfair_lock_unlock(&locks[index].lock) }
        return storage[key]
    }
    
    func remove(_ key: Key) {
        let index = lockIndex(for: key)
        os_unfair_lock_lock(&locks[index].lock)
        defer { os_unfair_lock_unlock(&locks[index].lock) }
        storage.removeValue(forKey: key)
    }
}

选择建议

使用 os_unfair_lock 当:

  • 需要高性能的同步

  • 锁持有时间很短

  • 不需要递归锁特性

  • 运行在 iOS 10+ / macOS 10.12+

继续使用 DispatchQueue 当:

  • 需要更高级的功能(如 barrier、async/sync 分离)

  • 需要递归锁

  • 需要在锁内执行异步操作

  • 代码需要在更老的系统版本运行

os_unfair_lock 在性能关键路径上是更好的选择,但需要更小心地使用以避免死锁。

相关推荐
初级代码游戏12 小时前
iOS开发 SwiftUI 8:NavigationView 导航
ios·swiftui·swift
美狐美颜SDK开放平台14 小时前
跨平台开发实战:直播美颜sdk动态贴纸在 Android / iOS / HarmonyOS 的落地方案
android·ios·harmonyos·美颜sdk·直播美颜sdk·视频美颜sdk·美颜api
2501_9160088914 小时前
在不越狱前提下导出 iOS 应用文件的过程,访问应用沙盒目录,获取真实数据
android·macos·ios·小程序·uni-app·cocoa·iphone
2501_9151063214 小时前
Android和IOS 移动应用App图标生成与使用 Assets.car生成
android·ios·小程序·https·uni-app·iphone·webview
2501_9159184114 小时前
Mac 抓包软件有哪些?Charles、mitmproxy、Wireshark和Sniffmaster哪个更合适
android·ios·小程序·https·uni-app·iphone·webview
2501_9151063214 小时前
iOS 抓包绕过 SSL 证书认证, HTTPS 暴力抓包、数据流分析
android·ios·小程序·https·uni-app·iphone·ssl
WeiAreYoung14 小时前
uni-app xcode 制作iOS Notification Service Extension 远程推送图文原生插件
ios·uni-app·xcode
2501_915921431 天前
iOS App 电耗管理 通过系统电池记录、Xcode Instruments 与克魔(KeyMob)组合使用
android·ios·小程序·https·uni-app·iphone·webview
且去填词1 天前
Context 详解:如何在微服务链路中传递取消信号与超时控制
ios·iphone
2501_915918411 天前
iOS App 测试方法,Xcode、TestFlight与克魔(KeyMob)等工具组合使用
android·macos·ios·小程序·uni-app·iphone·xcode