iOS中以NS開(kāi)頭常見(jiàn)的鎖的有NSCondition纤子、NSConditionLock胞此、NSLock、NSRecursiveLock涩金,其中NSCondition最為特別谱醇。
- NSCondition展示了更多的細(xì)節(jié),wait/signal/broadcast
- NSCondition的condition可以被忽略步做,那就和一般的鎖沒(méi)有區(qū)別.
- NSConditionLock和NSCondition都可以實(shí)現(xiàn)條件鎖副渴,區(qū)別在于NSConditionLock自身持有一個(gè)條件,而NSCondition的條件依賴(lài)于外部變量
NSCondition
lock & checkpoint全度,即充當(dāng)鎖又充當(dāng)檢查點(diǎn)佳晶。
__block int flag = 0;
NSCondition *condition = [NSCondition new];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[condition lock];
while (flag != 1) {
// 阻塞當(dāng)前線(xiàn)程,現(xiàn)在只能等待其他線(xiàn)程喚醒condition了
[condition wait];
}
// 需要加鎖保護(hù)的代碼
[condition unlock];
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
flag = 1;
// 隨機(jī)喚醒1個(gè)在等待 condition 的線(xiàn)程讼载,可以多次調(diào)用轿秧,喚醒多個(gè)線(xiàn)程
[cond signal];
// 喚醒所有在等待 condition 的線(xiàn)程
[cond broadcast];
});
可以看到,NSCondition可以主動(dòng)進(jìn)行wait/signal/broadcast咨堤。
在一個(gè)線(xiàn)程里加鎖要考慮的問(wèn)題:
1菇篡、加鎖失敗怎么處理?
- lock 阻塞當(dāng)前線(xiàn)程
- tryLock 不阻塞當(dāng)線(xiàn)程
2一喘、被阻塞的線(xiàn)程怎么恢復(fù)
signal:喚醒一個(gè)被condition阻塞的線(xiàn)程
broadcast:喚醒全部被condition阻塞的線(xiàn)程
wait/sigal這一套其實(shí)和信號(hào)量是一樣的驱还。
NSLock
The NSLock class uses POSIX threads to implement its locking behavior. When sending an unlock message to an NSLock object, you must be sure that message is sent from the same thread that sent the initial lock message. Unlocking a lock from a different thread can result in undefined behavior.
加鎖和解鎖必須在同一個(gè)線(xiàn)程嗜暴,否則會(huì)導(dǎo)致未知結(jié)果,只在NSLock的文檔里有這個(gè)警告议蟆。
NSLock *lock = [[NSLock alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lock];
// 需要加鎖保護(hù)的代碼
[lock unlock];
});
NSLock的lock和tryLock的區(qū)別
// bool success = [condition lock];
// while (!success) {
// [condition wait];
// }
[lock lock];
// bool success = [condition lock];
// while (!success) {
// do nothing
// }
bool success = [lock tryLock];
NSLock的unlock
// [condition unlock];
// [condition broadcast];
[lock unlock];
NSConditionLock
滿(mǎn)足條件時(shí)才能獲取鎖闷沥。在獲得鎖執(zhí)行保護(hù)區(qū)域代碼后,可以釋放鎖并重新設(shè)置條件咐容。
條件不滿(mǎn)足舆逃,阻塞當(dāng)前線(xiàn)程
__block int flag = 0;
NSConditionLock *lock = [[NSConditionLock alloc] initWithCondition:1];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// flag = 0 ; lock.condition = 1;
// flag != condition 無(wú)法獲得鎖,當(dāng)前線(xiàn)程進(jìn)入休眠,等待喚醒
// [condition lock];
// while (flag != condition) {
// [condition wait]
// }
[lock lockWhenCondition:flag];
// 需要加鎖保護(hù)的代碼
// lock.condition = 2;
// [conditon unlock];
// [condition broadcast];
[lock unlockWithCondition:2];
});
條件不滿(mǎn)足戳粒,阻塞路狮,后添加滿(mǎn)足,獲得鎖
__block int flag = 0;
NSConditionLock *lock = [[NSConditionLock alloc] initWithCondition:1];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lockWhenCondition:flag];
// 需要加鎖保護(hù)的代碼
[condition unlockWithCondition:2];
});
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// [condition unlock];
// [condition broadcast];
[lock unlockWithCondition:1];
});
信號(hào)量
// 設(shè)定一個(gè)信號(hào)蔚约,當(dāng)前可用為0
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"semaphore = 0 無(wú)法執(zhí)行");
// 如果 semaphore > 0 ,wait 會(huì)使 semaphore - 1奄妨,否則會(huì)阻塞當(dāng)前線(xiàn)程,所以不要主線(xiàn)程 wait
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"Run Task 1 Start");
sleep(1);
NSLog(@"Run Task 1 End");
dispatch_semaphore_signal(semaphore);
});
NSLog(@"semaphore 即將+1");
// semaphore + 1
dispatch_semaphore_signal(semaphore);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"semaphore = 0 無(wú)法執(zhí)行");
// 如果 semaphore > 0 ,wait 會(huì)使 semaphore - 1苹祟,否則會(huì)阻塞當(dāng)前線(xiàn)程砸抛,所以不要主線(xiàn)程 wait
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
NSLog(@"Run Task 2 Start");
sleep(1);
NSLog(@"Run Task 2 End");
dispatch_semaphore_signal(semaphore);
});
上面一點(diǎn)代碼和下面的代碼執(zhí)行結(jié)果沒(méi)有區(qū)別
__block NSUInteger flag = 0;
NSCondition *condition = [[NSCondition alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"semaphore = 0 無(wú)法執(zhí)行");
// 如果 semaphore > 0 ,wait 會(huì)使 semaphore - 1,否則會(huì)阻塞當(dāng)前線(xiàn)程树枫,所以不要主線(xiàn)程 wait
while (flag == 0) {
[condition wait];
}
flag--;
NSLog(@"Run Task 1 Start");
sleep(1);
NSLog(@"Run Task 1 End");
flag++;
[condition signal];
});
NSLog(@"semaphore 即將+1");
// semaphore + 1
flag++;
[condition broadcast];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSLog(@"semaphore = 0 無(wú)法執(zhí)行");
// 如果 semaphore > 0 ,wait 會(huì)使 semaphore - 1直焙,否則會(huì)阻塞當(dāng)前線(xiàn)程,所以不要主線(xiàn)程 wait
while (flag == 0) {
[condition wait];
}
flag--;
NSLog(@"Run Task 2 Start");
sleep(1);
NSLog(@"Run Task 2 End");
flag++;
[condition signal];
});
POSIX
Portable Operating System Interface of UNIX,一套通用的操作系統(tǒng)接口团赏。
NSLocking
- lock
- unlock
NSCondition箕般、NSConditionLock、NSLock舔清、NSRecursiveLock都實(shí)現(xiàn)了這個(gè)協(xié)議