ios中各种锁的对比

iOS各种锁的对比

为什么要引入锁?这是每个在学习ios锁的同学都会有的疑问。简单来说,ios语言是多线程的,当多个线程操作一个对象,且这个对象的操作要求是有序的时候,就需要的这个对象加锁。

eg:
    ios中存在一个数据库
    a/b/c/d业务都会像这个业务中存取数据
    a/b/c/d业务操作是异步的

就会存在这样一个情况,a在根据条件删除数据库中的数据,b在向数据库中添加数据。a/b是异步执行的,就可能a在执行的时候,b添加了元素,a继续执行,b添加的元素被删除。这样就与a执行完成在执行b冲突。

这个时候就引入了锁的概念

eg:
    生成一个锁保护数据库这个对象
    只有拥有当锁打开的时候,该对象才能备操作

各种锁的性能的对比

这里给出了几个性能性能对比的blog,详细的介绍了各种lock的使用场景以及时间消耗

iOS同步对象性能对比

不再安全的 OSSpinLock

Objective-C中不同方式实现锁

各种锁的使用场景

  • NSLock

相信大家接触最多的就是NSLock这个锁了,这个就不多用多说了。只要被NSLock锁中保护的对象,修改它只能在unlock的状态下

  • NSCondition

    从名字中可以知道,这是一个条件锁。主要的特点其实是在waitsignal这两个函数。当条件不满足时,wait,这个锁在了一个等待的状态,当我们再想让这个锁执行时,signal一个信号,中断的函数就会继续执行了

    • (void)wait; 挂起线程

    • (BOOL)waitUntilDate:(NSDate *)limit; 线程挂起到指定时间

    • (void)signal; 任意通知一个线程

    • (void)broadcast; 通知所用等待的线程

      eg:

      • 网络图片加载,下载图片时子线程wait
      • 当网络图片下载完成之后signal,中断wait调用主线程重新渲染UI
  • NSConditionLock

    从名字上看也是一个条件所,但是和之前的NSCondition有什么区别呢,我们看一下API,初始化条件锁,注意这个condition

    • (instancetype)initWithCondition:(NSInteger)condition NS_DESIGNATED_INITIALIZER;

初始化中的condition,readonly

  • property (readonly) NSInteger condition;

当条件满足时加锁

  • (void)lockWhenCondition:(NSInteger)condition;

尝试加锁,返回值为BOOL,这里先做判断为好

  • (BOOL)tryLock;

当满足条件时尝试加锁

  • (BOOL)tryLockWhenCondition:(NSInteger)condition;

当满足条件时尝试解锁

  • (void)unlockWithCondition:(NSInteger)condition;

在指定时间之前加锁

  • (BOOL)lockBeforeDate:(NSDate *)limit;

在指定时间之前条件满足时加锁

  • (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;

其实他的API已经解释了这个锁的使用环境

  • NSRecursiveLock

    从名字中大约知道这个锁实在递归中使用的。那么这个锁的用处在哪里?

    @property (nonatomic, strong) NSLock *lock;
    @property (nonatomic, strong) NSRecursiveLock *recursiveLock;

    • (void)viewDidLoad {
      [super viewDidLoad];
      [self recursiveFunction:100];
      }

    • (void)recursiveFunction:(NSInteger)condition {
      [self.lock lock];
      if (condition == 0) {

      return;

      } else {

      [self recursiveFunction:condition-1];

      }
      [self.lock unlock];
      }
      上面的函数执行的时候会崩溃,NSLock无法在同一线程下,没有unlock就再次持有这个锁,为了满足递归时对该对象的保护出现了NSRecursiveLock

      将self.lock替换成self.recursiveLock就可以执行了

    为什么换成了递归所就没有问题了呢?

那是因为,NSRecursiveLock类定义的锁可以在同一线程多次获得,而不会造成死锁。一个递归锁会跟踪它被多少次成功获得了。每次成功的获得该锁都必须平衡调用锁住和解锁的操作。只有所有的锁住和解锁操作都平衡的时候,锁才真正被释放给其他线程获得。

  • pthread_mutex_t

    这也是个互斥锁,只是更底层,C实现的锁,效率上也会更高

    可以看一下这个博客

    这个博客中有相关的举例

  • dispatch_barrier_async

    这里有一篇很好的文章介绍

  • @synchronized

    这也是一个互斥锁,相当于NSLock的封装版。相信大家用的也不少,虽然简化了很多,但是不推荐大家使用,自己在创建锁资源是比较耗时

总结

在对比了所有的锁之后,相信大家在面对资源读取的时候会有自己的初步判断了。至少我在搜集了这些资料之后里了解了更多,不是吗