浅谈iOS中的锁的介绍及使用

2020-01-21 02:17:48于海丽

用法:


- (void)viewDidLoad {
  [super viewDidLoad];

  [self nsrecursivelock];
}

- (void)nsrecursivelock{
  NSRecursiveLock * cjlock = [[NSRecursiveLock alloc] init];
  
  dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    static void (^RecursiveBlock)(int);
    RecursiveBlock = ^(int value) {
      [cjlock lock];
      NSLog(@"%d加锁成功",value);
      if (value > 0) {
        NSLog(@"value:%d", value);
        RecursiveBlock(value - 1);
      }
      [cjlock unlock];
      NSLog(@"%d解锁成功",value);
    };
    RecursiveBlock(3);
  });
}

控制台输出:

2017-10-19 16:15:40.584213+0800 Thread-Lock[39579:894111] 3加锁成功
2017-10-19 16:15:40.584387+0800 Thread-Lock[39579:894111] value:3
2017-10-19 16:15:40.584552+0800 Thread-Lock[39579:894111] 2加锁成功
2017-10-19 16:15:40.584635+0800 Thread-Lock[39579:894111] value:2
2017-10-19 16:15:40.584810+0800 Thread-Lock[39579:894111] 1加锁成功
2017-10-19 16:15:40.585267+0800 Thread-Lock[39579:894111] value:1
2017-10-19 16:15:40.585714+0800 Thread-Lock[39579:894111] 0加锁成功
2017-10-19 16:15:40.585906+0800 Thread-Lock[39579:894111] 0解锁成功
2017-10-19 16:15:40.586138+0800 Thread-Lock[39579:894111] 1解锁成功
2017-10-19 16:15:40.586217+0800 Thread-Lock[39579:894111] 2解锁成功
2017-10-19 16:15:40.586314+0800 Thread-Lock[39579:894111] 3解锁成功

由以上内容总结:

如果用 NSLock 的话,cjlock 先锁上了,但未执行解锁的时候,就会进入递归的下一层,而再次请求上锁,阻塞了该线程,线程被阻塞了,自然后面的解锁代码不会执行,而形成了死锁。而 NSRecursiveLock 递归锁就是为了解决这个问题。

2.3 NSConditionLock

NSConditionLock 对象所定义的互斥锁可以在使得在某个条件下进行锁定和解锁,它和 NSLock 类似,都遵循 NSLocking 协议,方法都类似,只是多了一个 condition 属性,以及每个操作都多了一个关于 condition 属性的方法,例如 tryLock、tryLockWhenCondition:,所以 NSConditionLock 可以称为条件锁。

    只有 condition 参数与初始化时候的 condition 相等,lock 才能正确进行加锁操作。 unlockWithCondition: 并不是当 condition 符合条件时才解锁,而是解锁之后,修改 condition 的值。

源码内容:


@interface NSConditionLock : NSObject <NSLocking> {
@private
  void *_priv;
}

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

@property (readonly) NSInteger condition;
- (void)lockWhenCondition:(NSInteger)condition;
- (BOOL)tryLock;
- (BOOL)tryLockWhenCondition:(NSInteger)condition;
- (void)unlockWithCondition:(NSInteger)condition;
- (BOOL)lockBeforeDate:(NSDate *)limit;
- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;

@property (nullable, copy) NSString *name API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0));

@end