參考 demo
參考的文章:
iOS開發(fā)中的11種鎖以及性能對比
多線程-線程安全
結(jié)論:
- 自旋鎖性能 > 信號量 > 互斥鎖
- 等待互斥鎖的線程會(huì)進(jìn)行休眠狀態(tài)避免繼續(xù)占用CPU資源
- 互斥的實(shí)現(xiàn)涉及到了可能發(fā)生的內(nèi)核態(tài)切換,線程休眠、喚醒等,如果臨界執(zhí)行代碼足夠小而快,不適合互斥鎖
- 等待自旋鎖的線程會(huì)進(jìn)入while循環(huán)中空轉(zhuǎn)等待
- 自旋的實(shí)現(xiàn)邏輯足夠簡單,只要標(biāo)記位的修改被設(shè)計(jì)為原子操作,就能保證多線程環(huán)境下的安全。對比互斥方案,自旋沒有線程切換、休眠喚醒的開銷。但是空轉(zhuǎn)的代碼會(huì)導(dǎo)致CPU在等待期間是滿負(fù)荷執(zhí)行的,如果加鎖的代碼不夠小而快,甚至?xí)苯佑绊懙匠绦虻倪\(yùn)行
互斥鎖
- NSLock
//初始化
self.array = @[].mutableCopy;
self.lock = [[NSLock alloc] init];
self.lock.name = @"com.example.lock.nslock";
//多線程,訪問臨界區(qū)
[self.lock lock];
[self.array addObject:number];
[self.lock unlock];
- pthread_mutex_t
//頭文件
#import <pthread.h>
//定義
pthread_mutex_t mutex;
//初始化
self.array = @[].mutableCopy;
pthread_mutex_init(&mutex,NULL);
//多線程,訪問臨界區(qū)
pthread_mutex_lock(&mutex);
[self.array addObject:number];
pthread_mutex_unlock(&mutex);
//dealloc
pthread_mutex_destroy(&mutex);
- @synchronized
@synchronized (self) {
[self.array addObject:number];
}
自旋鎖
- OSSpinLock (廢棄)
存在的問題,優(yōu)先級反轉(zhuǎn):
如果一個(gè)低優(yōu)先級的線程獲得鎖并訪問共享資源,這時(shí)一個(gè)高優(yōu)先級的線程也嘗試獲得這個(gè)鎖,它會(huì)處于 spin lock 的忙等狀態(tài)從而占用大量 CPU。此時(shí)低優(yōu)先級線程無法與高優(yōu)先級線程爭奪 CPU 時(shí)間,從而導(dǎo)致任務(wù)遲遲完不成、無法釋放 lock
#import <libkern/OSAtomic.h>
OSSpinLock lock = OS_SPINLOCK_INIT;
OSSpinLockLock(&lock);
//臨界區(qū)代碼
OSSpinLockUnlock(&lock);
- os_unfair_lock(OSSpinLock的替代方案,iOS10.0以后可用)
#import <os/lock.h>
os_unfair_lock_t unfairLock;
unfairLock = &(OS_UNFAIR_LOCK_INIT);
os_unfair_lock_lock(unfairLock);
//臨界區(qū)代碼
os_unfair_lock_unlock(unfairLock);
信號量
dispatch_semaphore_create(long value); // 創(chuàng)建信號量
dispatch_semaphore_wait(dispatch_semaphore_t dsema, dispatch_time_t timeout); // 等待信號量
//臨界區(qū)的代碼
dispatch_semaphore_signal(dispatch_semaphore_t deem); // 發(fā)送信號量
使用barrier
dispatch_queue_t queue = dispatch_queue_create("queue.concurrent", DISPATCH_QUEUE_CONCURRENT);
__block int value = 1;
dispatch_async(queue, ^{
NSLog(@"task1,value = %d",value);
});
dispatch_async(queue, ^{
NSLog(@"task2, value = %d",value);
});
dispatch_barrier_async(queue, ^{
value = 2;
NSLog(@"barrier, modify value to %d", value);
});
dispatch_async(queue, ^{
NSLog(@"task3, value = %d",value);
});