OSSpinLock
NSString *phoneVersion = [UIDevice currentDevice].systemVersion;
if (phoneVersion.floatValue >= 10.0) {
// 線程1
__block os_unfair_lock lock = OS_UNFAIR_LOCK_INIT;
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"準(zhǔn)備上鎖1");
if (os_unfair_lock_trylock(&lock)) { // 嘗試加鎖 可以加鎖則立即加鎖并返回YES昆稿,反之返回NO
// 這里順便提一下trylock和lock使用場景:
// 當(dāng)前線程鎖失敗向族,也可以繼續(xù)其它任務(wù),用 trylock 合適
// 當(dāng)前線程只有鎖成功后腐宋,才會做一些有意義的工作喇完,那就 lock,沒必要輪詢 trylock
}
os_unfair_lock_lock(&lock); // 加鎖
os_unfair_lock_unlock(&lock); // 解鎖
});
}else {
// 線程1
__block OSSpinLock lock = OS_SPINLOCK_INIT;
dispatch_async(dispatch_get_main_queue(), ^{
NSLog(@"準(zhǔn)備上鎖1");
if (OSSpinLockTry(&lock)) { // 嘗試加鎖
// 這里順便提一下trylock和lock使用場景:
// 當(dāng)前線程鎖失敗蹬耘,也可以繼續(xù)其它任務(wù)钮科,用 trylock 合適
// 當(dāng)前線程只有鎖成功后,才會做一些有意義的工作婆赠,那就 lock绵脯,沒必要輪詢 trylock
}
OSSpinLockLock(&lock); // 加鎖
OSSpinLockUnlock(&lock); // 解鎖
});
}
- 如果一個低優(yōu)先級的線程獲得鎖并訪問共享資源佳励,這時一個高優(yōu)先級的線程也嘗試獲得這個鎖,它會處于
spin lock
的忙等狀態(tài)從而占用大量CPU
蛆挫。此時低優(yōu)先級線程無法與高優(yōu)先級線程爭奪CPU
時間赃承,從而導(dǎo)致任務(wù)遲遲完不成、無法釋放lock
悴侵。這并不只是理論上的問題瞧剖,libobjc
已經(jīng)遇到了很多次這個問題了,于是蘋果的工程師停用了OSSpinLock
可免。
dispatch_semaphore_t 信號量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(10); // 傳入的值必須大于等于0抓于,若傳入0則阻塞線程并等待timeout,時間到后會執(zhí)行其后的語句
dispatch_time_t overTime = dispatch_time(DISPATCH_TIME_NOW, 3.0f * NSEC_PER_SEC);
// 線程1
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
dispatch_semaphore_wait(semaphore, overTime); // signal值 +1
NSLog(@"執(zhí)行耗時操作");
dispatch_semaphore_signal(semaphore); // signal值 -1
});
關(guān)于信號量浇借,我們可以用停車來比喻:
- 停車場剩余4個車位捉撮,那么即使同時來了四輛車也能停的下。如果此時來了五輛車妇垢,那么就有一輛需要等待巾遭。
- 信號量的值
(signal)
就相當(dāng)于剩余車位的數(shù)目,dispatch_semaphore_wait
函數(shù)就相當(dāng)于來了一輛車闯估,dispatch_semaphore_signal
就相當(dāng)于走了一輛車灼舍。停車位的剩余數(shù)目在初始化的時候就已經(jīng)指明了(dispatch_semaphore_create(long value))
,調(diào)用一次dispatch_semaphore_signal
涨薪,剩余的車位就增加一個骑素;調(diào)用一次dispatch_semaphore_wait
剩余車位就減少一個;當(dāng)剩余車位為 0 時刚夺,再來車(即調(diào)用 dispatch_semaphore_wait)
就只能等待献丑。有可能同時有幾輛車等待一個停車位。有些車主沒有耐心光督,給自己設(shè)定了一段等待時間阳距,這段時間內(nèi)等不到停車位就走了塔粒,如果等到了就開進(jìn)去停車结借。而有些車主就像把車停在這,所以就一直等下去卒茬。
pthread_mutex 互斥鎖 需要引入頭文件 <pthread.h>
static pthread_mutex_t pLock;
pthread_mutex_init(&pLock, NULL);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
pthread_mutex_lock(&pLock); // 加鎖
sleep(3); // 模擬耗時
pthread_mutex_unlock(&pLock); // 解鎖
});
pthread_mutex(recursive) 遞歸鎖
static pthread_mutex_t pLock2;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr); // 初始化attr并且給它賦予默認(rèn)
pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); // 設(shè)置鎖類型船老,這邊是設(shè)置為遞歸鎖
pthread_mutex_init(&pLock2, &attr);
pthread_mutexattr_destroy(&attr); // 銷毀一個屬性對象,在重新進(jìn)行初始化之前該結(jié)構(gòu)不能重新使用
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
static void (^RecursiveBlock)(int);
RecursiveBlock = ^(int value) {
pthread_mutex_lock(&pLock2);
if (value > 0) {
NSLog(@"value : %d",value);
RecursiveBlock(value - 1);
}
pthread_mutex_unlock(&pLock2);
};
RecursiveBlock(5);
});
NSLock 普通鎖
NSLock *lock = [[NSLock alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[lock lock]; // 加鎖
[lock unlock]; // 解鎖
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 嘗試加速
BOOL x = [lock lockBeforeDate:[NSDate dateWithTimeIntervalSinceNow:4]];
if (x) {
[lock unlock];
}else {
NSLog(@"失敗");
}
});
NSCondition
NSCondition *cLock = [[NSCondition alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
[cLock lock]; // 加鎖
[cLock waitUntilDate:[NSDate dateWithTimeIntervalSinceNow:2]]; // 線程等待兩秒
[cLock wait]; // 線程等待
[cLock signal]; // 喚醒一個等待的線程
[cLock broadcast]; // 喚醒所有等待的線程
[cLock unlock]; // 解鎖
});
NSRecursiveLock 遞歸鎖
NSRecursiveLock *rLock = [[NSRecursiveLock alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
static void(^RecursiveBlock)(int);
RecursiveBlock = ^(int value){
[rLock tryLock];
if (value > 0) {
RecursiveBlock(value - 1);
}
[rLock unlock];
};
RecursiveBlock(4);
});
@synchronized 條件鎖
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized (self) {
sleep(2);
NSLog(@"@synchronized線程");
}
});
NSConditionLock 條件鎖
NSConditionLock *cLock2 = [[NSConditionLock alloc] init];
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if ([cLock2 tryLockWhenCondition:0]) {
NSLog(@"NSConditionLock線程1");
[cLock2 unlockWithCondition:1];
} else {
NSLog(@"失敗");
}
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if ([cLock2 tryLockWhenCondition:3]) {
// [cLock2 lockWhenCondition:3];
NSLog(@"NSConditionLock線程2");
[cLock2 unlockWithCondition:2];
} else {
NSLog(@"失敗");
}
});
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
if ([cLock2 tryLockWhenCondition:1]) {
NSLog(@"NSConditionLock線程3");
[cLock2 unlockWithCondition:3];
}
});
- 我們在初始化
NSConditionLock
對象時圃酵,給了他的標(biāo)示為 0- 執(zhí)行
tryLockWhenCondition:
時柳畔,我們傳入的條件標(biāo)示也是 0,所 以線程1 加鎖成功- 執(zhí)行
unlockWithCondition:
時,這時候會把condition
由 0 修改為 1- 因為
condition
修改為了 1郭赐, 會先走到 線程3薪韩,然后 線程3 又將condition
修改為 3- 最后 走了 線程2 的流程
- 從上面的結(jié)果我們可以發(fā)現(xiàn),
NSConditionLock
還可以實現(xiàn)任務(wù)之間的依賴。