你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> NSRecursiveLock遞歸鎖的使用

NSRecursiveLock遞歸鎖的使用

編輯:IOS開發基礎

1.jpg

NSRecursiveLock實際上定義的是一個遞歸鎖,這個鎖可以被同一線程多次請求,而不會引起死鎖。這主要是用在循環或遞歸操作中。我們先來看一個示例:

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是遞歸調用的。所以每次進入這個block時,都會去加一次鎖,而從第二次開始,由於鎖已經被使用了且沒有解鎖,所以它需要等待鎖被解除,這樣就導致了死鎖,線程被阻塞住了。調試器中會輸出如下信息:

value = 5
*** -[NSLock lock]: deadlock ( '(null)')   *** Break on _NSLockError() to debug.

在這種情況下,我們就可以使用NSRecursiveLock。它可以允許同一線程多次加鎖,而不會造成死鎖。遞歸鎖會跟蹤它被lock的次數。每次成功的lock都必須平衡調用unlock操作。只有所有達到這種平衡,鎖最後才能被釋放,以供其它線程使用。

所以,對上面的代碼進行一下改造,

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

這樣,程序就能正常運行了,其輸出如下所示:

value = 5
value = 4
value = 3
value = 2
value = 1

NSRecursiveLock除了實現NSLocking協議的方法外,還提供了兩個方法,分別如下:

// 在給定的時間之前去嘗試請求一個鎖
- (BOOL)lockBeforeDate:(NSDate *)limit

// 嘗試去請求一個鎖,並會立即返回一個布爾值,表示嘗試是否成功
- (BOOL)tryLock

這兩個方法都可以用於在多線程的情況下,去嘗試請求一個遞歸鎖,然後根據返回的布爾值,來做相應的處理。如下代碼所示:

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");
    }
});

在前面的代碼中,我們又添加了一段代碼,增加一個線程來獲取遞歸鎖。我們在第二個線程中嘗試去獲取遞歸鎖,當然這種情況下是會失敗的,輸出結果如下:

value = 5
value = 4
fail to lock before date
value = 3
value = 2
value = 1

另外,NSRecursiveLock還聲明了一個name屬性,如下:

@property(copy) NSString *name

我們可以使用這個字符串來標識一個鎖。Cocoa也會使用這個name作為錯誤描述信息的一部分。

參考

  1. NSRecursiveLock Class Reference

  2. Objective-C中不同方式實現鎖(二)

  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved