「这是我参与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: