我们使用 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 不能递归使用,即同一个线程不能多次锁定,否则会导致死锁。
我们使用以下步骤:
-
声明一个 os_unfair_lock 属性,并初始化为 OS_UNFAIR_LOCK_INITIALIZER。
-
在需要加锁的代码块中,使用 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_lock比DispatchQueue性能更高,尤其是在高频锁操作场景 -
内存占用更小(仅 4 字节)
-
没有线程优先级反转问题
重要注意事项:
-
不可递归锁
// ❌ 错误:会导致死锁
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 在性能关键路径上是更好的选择,但需要更小心地使用以避免死锁。