- NSRecursiveLock遞歸鎖
所謂遞歸鎖,就是在同一線程上該鎖是可重入的,它對於不同線程相當於普通的互斥鎖。NSRecursiveLock類定義的鎖可以在同一線程多次lock,而不會造成死鎖。遞歸鎖會跟蹤它被多少次lock。每次成功的lock都必須平衡調用unlock操作。只有所有的鎖住和解鎖操作都平衡的時候,鎖才真正被釋放給其他線程獲得。
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");
}
});
代碼分析:第一個異步dispatch創建了一個新的線程,並加入了遞歸鎖,此時,在第二個異步dispatch創建的新線程中,判斷當前的遞歸鎖的狀態。
2. NSConditionLock條件鎖
普通的互斥鎖和遞歸鎖都只考慮鎖和解鎖的問題,這樣的鎖無法滿足多線程對訪問共享資源的各種需求。因此,條件鎖(NSConditionLock)的出現可以解決多線程技術中需要滿足特定條件才能解開某些鎖的場景。
//主線程中
NSConditionLock *conditionLock = [[NSConditionLock alloc] init];
//異步線程1 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
for (int i=0;i<=2;i++)
{
//創建一個不需要條件的鎖
[conditionLock lock];
NSLog(@"thread1:%d",i);
sleep(2);
[conditionLock unlockWithCondition:i];
}
});
//異步線程2
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//設置一個條件鎖,需要對應的unlockWithCondition:2才能解開
[conditionLock lockWhenCondition:2];
NSLog(@"thread2");
[conditionLock unlock];
});
代碼分析:異步線程1創建了一個沒有開鎖條件的條件鎖,而異步線程2併發的創建了一個開鎖條件爲2的條件鎖,當線程1中的循環變量i=2時,線程2中的條件鎖被解開。
3. NSDistributedLock分佈式鎖
對於多個進程或多個程序之間需要構建互斥的場景時,使用上述多線程間的鎖就無法滿足需求。此時,需要使用到分佈式鎖。分佈式鎖是通過文件系統實現的,它不繼承自NSLock,因而也沒有實現lock方法,但它提供了tryLock,unlock,breakLock等方法,如果需要lock,則必須自己實現一個trylock的輪詢。
應用A:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//進程間互斥所用的鎖
NSDistributedLock *lock = [[NSDistributedLock alloc] initWithPath:@"/Users/mac/Desktop/earning__"];
[lock breakLock];
[lock tryLock];
sleep(10);
[lock unlock];
NSLog(@"appA: OK");
});
應用B:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSDistributedLock *lock = [[NSDistributedLock alloc] initWithPath:@"/Users/mac/Desktop/earning__"];
while (![lock tryLock]) {
NSLog(@"appB: waiting");
sleep(1);
}
[lock unlock];
NSLog(@"appB: OK");
});