原文,此文只為總結(jié)學(xué)習(xí)使用
NSRecursiveLock實際上定義的是一個遞歸鎖,這個鎖可以被同一線程多次請求,而不會引起死鎖。這主要是用在循環(huán)或遞歸操作中。我們先來看一個示例:
NSLock *lock = [[NSLock alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 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);
});
這段代碼是一個典型的死鎖情況。在我們的線程中,RecursiveMethod是遞歸調(diào)用的。所以每次進(jìn)入這個block時,都會去加一次鎖,而從第二次開始,由于鎖已經(jīng)被使用了且沒有解鎖,所以它需要等待鎖被解除,這樣就導(dǎo)致了死鎖,線程被阻塞住了。調(diào)試器中會輸出如下信息:
value = 5
*** -[NSLock lock]: deadlock ( '(null)') *** Break on _NSLockError() to debug.
在這種情況下,我們就可以使用NSRecursiveLock。它可以允許同一線程多次加鎖,而不會造成死鎖。遞歸鎖會跟蹤它被lock的次數(shù)。每次成功的lock都必須平衡調(diào)用unlock操作。只有所有達(dá)到這種平衡,鎖最后才能被釋放,以供其它線程使用。
所以,對上面的代碼進(jìn)行一下改造,
NSRecursiveLock *lock = [[NSRecursiveLock alloc] init];
這樣,程序就能正常運(yùn)行了,其輸出如下所示:
value = 5
value = 4
value = 3
value = 2
value = 1
NSRecursiveLock除了實現(xiàn)NSLocking協(xié)議的方法外,還提供了兩個方法,分別如下:
// 在給定的時間之前去嘗試請求一個鎖
- (BOOL)lockBeforeDate:(NSDate *)limit
// 嘗試去請求一個鎖,并會立即返回一個布爾值,表示嘗試是否成功
- (BOOL)tryLock
這兩個方法都可以用于在多線程的情況下,去嘗試請求一個遞歸鎖,然后根據(jù)返回的布爾值,來做相應(yīng)的處理。如下代碼所示:
NSRecursiveLock *lock = [[NSRecursiveLock alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 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);
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
sleep(2);
BOOL flag = [lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:1]];
if (flag) {
NSLog(@"lock before date");
[lock unlock];
} else {
NSLog(@"fail to lock before date");
}
});
在前面的代碼中,我們又添加了一段代碼,增加一個線程來獲取遞歸鎖。我們在第二個線程中嘗試去獲取遞歸鎖,當(dāng)然這種情況下是會失敗的,輸出結(jié)果如下:
value = 5
value = 4
fail to lock before date
value = 3
value = 2
value = 1
另外,NSRecursiveLock還聲明了一個name屬性,如下:
@property(copy) NSString *name
我們可以使用這個字符串來標(biāo)識一個鎖。Cocoa也會使用這個name作為錯誤描述信息的一部分。