swift 的几种锁

1、NSLock

NSLock 是最基本的锁,提供了传统的锁定和解锁机制。
场景:在多线程环境下保护一个简单的资源。

Import Foundation
class Counter {
    private var value = 0
    private let lock = NSLock()
    
    func increment() {
        lock.lock()
        value += 1
        lock.unlock()
    }
    
    func getValue() -> Int {
        lock.lock()
        let currentValue = value
        lock.unlock()
        return currentValue
    }
}

let counter = Counter()
DispatchQueue.concurrentPerform(iterations: 100) { _ in
    counter.increment()
}
print("Final counter value: \(counter.getValue())")  // 应该输出:100

2、NSRecursiveLock

NSRecursiveLock 允许同一线程多次获取同一锁,而不会导致死锁。
场景:在同一个线程中多次递归调用需要加锁的代码。

Import Foundation

class RecursiveCounter {
    private var value = 0
    private let lock = NSRecursiveLock()
    
    func increment() {
        lock.lock()
        value = recursiveIncrement(value: value)
        lock.unlock()
    }
    
    private func recursiveIncrement(value: Int) -> Int {
        lock.lock()
        defer { lock.unlock() }
        
        if value < 10 {
            return recursiveIncrement(value: value + 1)
        } else {
            return value
        }
    }
    
    func getValue() -> Int {
        lock.lock()
        let currentValue = value
        lock.unlock()
        return currentValue
    }
}

let recursiveCounter = RecursiveCounter()
recursiveCounter.increment()
print("Final counter value: \(recursiveCounter.getValue())")  // 应该输出:10

3、NSCondition / NSConditionLock

NSCondition 结合了锁和条件变量,适用于需要线程等待某个特定条件满足的情况。
场景:一组线程需要等待某个特定条件满足才能继续执行。

Import Foundation

class DataBuffer {
    private var buffer: [Int] = []
    private let condition = NSCondition()
    
    func produce(value: Int) {
        condition.lock()
        buffer.append(value)
        condition.signal() // 唤醒等待该条件的线程
        condition.unlock()
    }
    
    func consume() -> Int? {
        condition.lock()
        while buffer.isEmpty {
            condition.wait() // 等待直到有数据可消费
        }
        let value = buffer.removeFirst()
        condition.unlock()
        return value
    }
}

let buffer = DataBuffer()
DispatchQueue.global().async {
    for i in 0..<10 {
        buffer.produce(value: i)
        sleep(1)  // 模拟生产延迟
    }
}

DispatchQueue.global().async {
    for _ in 0..<10 {
        if let value = buffer.consume() {
            print("Consumed: \(value)")
        }
    }
}
import Foundation

// 定义一个用于存储数据的简单类
class SharedResource {
    var data: [String] = []
    var conditionLock = NSConditionLock(condition: 0) // 初始条件为0
}

let sharedResource = SharedResource()

// 生产者线程
let producer = Thread {
    for i in 1...5 {
        sharedResource.conditionLock.lock(whenCondition: 0)
        print("Producer: Producing item \(i)")
        sharedResource.data.append("Item \(i)")
        sharedResource.conditionLock.unlock(withCondition: 1) // 生产完成,更新条件
        sleep(1) // 模拟生产时间
    }
}

// 消费者线程
let consumer = Thread {
    for _ in 1...5 {
        sharedResource.conditionLock.lock(whenCondition: 1)
        if let item = sharedResource.data.first {
            print("Consumer: Consuming \(item)")
            sharedResource.data.removeFirst()
        }
        sharedResource.conditionLock.unlock(withCondition: 0) // 消费完成,更新条件
        sleep(2) // 模拟消费时间
    }
}

// 启动生产者和消费者线程
producer.start()
consumer.start()

// 等待线程完成
producer.join()
consumer.join()

print("All items processed.")

4、DispatchSemaphore

DispatchSemaphore 提供了一种基于计数信号量的线程同步机制。
场景:控制同一时间只能有指定数量的线程访问某个资源。

Import Dispatch
let semaphore = DispatchSemaphore(value: 3)
for i in 0..<10 {
    DispatchQueue.global().async {
        semaphore.wait() // 等待信号量
        print("Task \(i) started.")
        sleep(2) // 模拟任务执行
        print("Task \(i) finished.")
        semaphore.signal() // 释放信号量
    }
}

5、DispatchQueue (穿行队列)

使用 GCD (Grand Central Dispatch) 的串行队列,可以确保队列中的任务按顺序执行,从而实现线程安全。
场景:按顺序执行任务,保护资源访问。

Import Dispatch
let serialQueue = DispatchQueue(label: "com.example.myserialqueue")
var sharedResource = [Int]()
for i in 0..<10 {
    serialQueue.async {
        sharedResource.append(i)
        print("Appended \(i)")
    }
}

6、os_unfair_lock

os_unfair_lock 是一种低级、高性能的锁,适用于需要较高性能的锁操作环境。
场景:需要高性能且明确知道只在较短代码段中使用锁。

import os.lock

class UnfairLockCounter {
    private var value = 0
    private var lock = os_unfair_lock_s()
    
    func increment() {
        os_unfair_lock_lock(&lock)
        value += 1
        os_unfair_lock_unlock(&lock)
    }
    
    func getValue() -> Int {
        os_unfair_lock_lock(&lock)
        let currentValue = value
        os_unfair_lock_unlock(&lock)
        return currentValue
    }
}

let unfairCounter = UnfairLockCounter()
DispatchQueue.concurrentPerform(iterations: 100) { _ in
    unfairCounter.increment()
}
print("Final counter value: \(unfairCounter.getValue())")  // 应该输出:100

7、@ synchronized

Swift 本身没有直接的 @synchronized 关键字,但可以通过扩展 NSObject 来实现类似的功能。

Import Foundation
func synchronized (_ lock: AnyObject, closure: () -> Void) {
    objc_sync_enter(lock)
    closure()
    objc_sync_exit(lock)
}
let lockObject = NSObject()
synchronized(lockObject) {
    // 需要保护的代码区域
}

8、swift 5.5 可以使用actor来保证线程同步问题

可以参考:https://www.bennyhuo.com/2022/01/22/swift-coroutines-04-structured-concurrency/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容

  • 学习写简书博客,每次写简书都是对过往的回顾 老生常谈 无并发,不编程.提到多线程就很难绕开锁. iOS开发中较常见...
    cs_mark阅读 522评论 0 0
  • 前言 多线程开发是性能优化常用的技术,在多线程开发中,线程安全是绕不开的一个话题。线程安全的定义,在之前的文章中也...
    虎啦吧唧的猴阅读 1,094评论 0 2
  • 原文Thread Safety in Swift[https://swiftrocks.com/thread-sa...
    雾霾下的天空阅读 506评论 0 0
  • synchronized, NSLock, 递归锁, 条件锁 图中锁的性能从高到底依次是:OSSpinLock(自...
    为了自由的白菜阅读 93评论 0 1
  • 本文主要介绍常见的锁,以及synchronized、NSLock、递归锁、条件锁的底层分析 锁 先看一张大家都非常...
    北京_小海阅读 519评论 0 0