iOS中的线程锁(关于NSRecursiveLock)

「这是我参与11月更文挑战的第18天,活动详情查看:2021最后一次更文挑战

NSRecursiveLock(递归锁)

NSRecursiveLock 概念

在实际开发中,在调用 lock 之前,NSLock 必须先调用 unlock。但是递归锁不是这样的,NSRecursiveLock 是一个递归锁,一般执行递归操作的时候使用的锁。属于互斥锁中的递归锁,可被同一线程多次获取的锁,而不会产生死锁。通俗的讲,一个线程已经获得了锁,开始执行受锁保护的代码(还未被解锁),如果这段代码调用了其他函数,而被调用的函数又要获取这个锁,此时已然可以获得锁并正常执行,而不会死锁,前提是在同一线程

NSRecursiveLock 常用方法 <遵守 NSLocking 协议>

@protocol NSLocking

- (void)lock;
- (void)unlock;

@end

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

- (BOOL)tryLock;
- (BOOL)lockBeforeDate:(NSDate *)limit;

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

@end
复制代码

NSRecursiveLock 常用场景

先来看一个典型的死锁情况

示例:

NSLock *lock = [[NSLock alloc] init];

dispatch_async(dispatch_get_global_queue(0, 0), ^{

   static void (^recursiveMethod)(int);
   recursiveMethod = ^(int value){
        
       [lock lock];
       if (value > 0) {
           NSLog(@"value==%d",value);
           sleep(2);
           recursiveMethod(value - 1);
       }
       [lock unlock];
   };
   recursiveMethod(5);
});

log:
value==5
复制代码

简单分析:

RecursiveMethod 是递归调用的。所以每次进入这个block时,都会去加一次锁,而从第二次开始,由于锁已经被使用了且没有解锁,所以它需要等待锁被解除,这样就导致了死锁,线程被阻塞住了,所以控制台只输出了一行

在这种情况下,可以使用 NSRecursiveLock。递归锁会跟踪它被 lock 的次数。每次成功的 lock 都必须平衡调用 unlock 操作。只有所有达到这种平衡,锁最后才能被释放,以供其它线程使用

示例:

NSRecursiveLock *lock = [[NSRecursiveLock alloc] init];

dispatch_async(dispatch_get_global_queue(0, 0), ^{
    static void (^recursiveMethod)(int);
    recursiveMethod = ^(int value){
        [lock lock];
        if (value > 0) {
            NSLog(@"value==%d",value);
            recursiveMethod(value - 1);
        }
        [lock unlock];
    };
    recursiveMethod(5);
});
复制代码

log:

Snip20211118_1.png

猜你喜欢

转载自juejin.im/post/7031824170883383333