IMG_5746.JPG

锁的种类

  • 锁可以分为两大类,自旋锁和互斥锁
    • 互斥锁:互斥 + 同步,两条线程同时处理任务,互斥:A走B不能走,同步:按照相应的顺序先后走,闲等
      • 同步 = 互斥 + 顺序,相当于更加严厉的互斥
    • 自旋锁:A走,B在死等,忙等
  • NSRecursiveLock 同样具备递归性(解决了NSLock的无法递归性),但无法多线程
  • @synchronized 具备多线程递归性(解决了NSrecursiveLock无法多线程),使用场景广泛

NSCondition

  • NSCondition的对象实际上作为一个锁和一个线程检查器:
    • 锁主要为了当检测条件时保护数据源,执行条件引发的任务
    • 线程检查器主要是根据条件决定是否继续运行线程,即线程是否被阻塞

未命名文件 (5).jpg

补充

读写锁实现

  • 方法一、pthread
  • 方法二、GCD
  • 满足特性
    • 多读单写
    • 写 和 写 互斥
    • 读 和 写 互斥
    • 写的时候不能堵塞任务执行
  • 栅栏函数 写(自定义的并发队列),下面的操作不能走,使用dispatch_barrier_async
  • 读:多读 dispatch_sync 同步 多读(并发队列)

image.png

  • 多读是线程和线程间多读,同时保证了读写互斥功能

IMG_AFF0E89A799F-1.jpeg

举例

  • 以下代码在运行时,因为多线程原因,导致打印数据紊乱

image.png

  • 解决方案1:可以通过添加NSLock解决
    • 核心的业务代码在testMethod(10)处,所以锁这里
    • 注意:避免NSLock与业务代码锁在一起,保证业务代码块的安全
    • NSLock可以多线程,但不具备递归性

image.png

  • NSRecuresiveLock使用加锁,只能打印一次10~1
    • NSRecuresiveLock递归锁不具备多线程性
    • 因此使用@synchronized即可多线程又可递归 ```objectivec
  • (void)lg_testRecursive{ for (int i= 0; i<10; i++) {

    1. dispatch_async(dispatch_get_global_queue(0, 0), ^{
    2. static void (^testMethod)(int);
    3. testMethod = ^(int value){
    4. [self.recursiveLock lock];
    5. if (value > 0) {
    6. NSLog(@"current value = %d",value);
    7. testMethod(value - 1);
    8. }
    9. [self.recursiveLock unlock];
    10. };
    11. testMethod(10);
    12. });

    } } ```

  • NSCondition 跟信号量类似,相当于两把锁+信号量

未命名文件 (33).jpg

  • NSLock,遵循了NSLocking协议,底层封装了pthread_mutex_init(mutex, nil),调用pthread_mutex_lock
  • NSRecuresiveLock,底层同样是对pthread_mutex_lock进行调用,与NSLock不同的是,其底层settype = PTHREAD_MUTEX_RECURSIVE
  • NSCondictionLock,底层也是封装了pthread_mutext_lock,额外添加了condition的条件pthread_cond_wait

    NSCondictionLock

  • 以下代码执行顺序3 -> 2 -> 1,2一定在1前面执行,满足条件才能执行,3没有条件控制,直接执行

  • 底层封装了NSCondition

image.png