“This is the 18th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021”
NSRecursiveLock
NSRecursiveLock concept
In real development, NSLock must call UNLOCK before calling lock. NSRecursiveLock is a recursive lock that is used when performing recursive operations. A recursive lock in a mutex that can be acquired more than once by the same thread without causing a deadlock. In layman’s terms, a thread has acquired a lock and starts executing code protected by the lock (which has not yet been unlocked). If this code calls another function and the function that is called acquires the lock, the lock can already be acquired and executed without deadlock, provided that the lock is on the same thread
NSRecursiveLock common < complyNSLocking
Agreement >
@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
Copy the code
NSRecursiveLock Common scenario
Let’s start with a typical deadlock situation
Example:
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
Copy the code
Simple analysis:
RecursiveMethod is called recursively. So every time it enters this block, it adds a lock, and from the second time, since the lock is already in use and not unlocked, it has to wait for the lock to be unlocked, which causes a deadlock, and the thread is blocked, so the console just prints out one line
In this case, NSRecursiveLock can be used. A recursive lock keeps track of how many times it is locked. Each successful lock must balance calls to unlock. Only when this balance is reached can the lock finally be released for use by other threads
Example:
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);
});
Copy the code
The log: