鎖 是什么意思?
-
我們在使用多線程的時候多個線程可能會訪問同一塊資源,這樣就很容易引發數據錯亂和數據安全等問題,這時候就需要我們保證每次只有一個線程訪問這一塊資源,鎖 應運而生。
-
這里順便提一下,上鎖的兩種方式trylock和lock使用場景:
當前線程鎖失敗,也可以繼續其它任務,用 trylock 合適
當前線程只有鎖成功后,才會做一些有意義的工作,那就 lock,沒必要輪詢 trylock
注:以下大部分鎖都會提供trylock接口,不再作解釋
性能圖
<准備操作>
測試代碼
#define RHTICK NSDate *startTime = [NSDate date];
#define RHTOCK NSLog(@"==========Time: %f", -[startTime timeIntervalSinceNow]);
NSUInteger count = 1000*10000;//執行一千萬次
RHTICK
for(int i=0; i<count; i++) {
加鎖
解鎖
}
RHTOCK
注:測試中執行時間會波動,所以我取的平均值.
一、OSSpinLock (自旋鎖)
測試中效率最高的鎖, 不過經YYKit作者確認, OSSpinLock已經不再線程安全,OSSpinLock有潛在的優先級反轉問題.不再安全的 OSSpinLock;
0.097348s
需要導入頭文件
#import <libkern/OSAtomic.h>
// 初始化
OSSpinLock spinLock = OS_SPINLOCK_INIT;
// 加鎖
OSSpinLockLock(&spinLock);
// 解鎖
OSSpinLockUnlock(&spinLock);
// 嘗試加鎖,可以加鎖則立即加鎖並返回 YES,反之返回 NO
OSSpinLockTry(&spinLock)
/*
注:蘋果爸爸已經在iOS10.0以后廢棄了這種鎖機制,使用os_unfair_lock 替換,
顧名思義能夠保證不同優先級的線程申請鎖的時候不會發生優先級反轉問題.
*/
二、os_unfair_lock(自旋鎖)
0.171789s
需要導入頭文件
#import <os/lock.h>
// 初始化
os_unfair_lock unfair_lock = OS_UNFAIR_LOCK_INIT;
// 加鎖
os_unfair_lock_lock(&unfair_lock);
// 解鎖
os_unfair_lock_unlock(&unfair_lock);
// 嘗試加鎖,可以加鎖則立即加鎖並返回 YES,反之返回 NO
os_unfair_lock_trylock(&unfair_lock);
/*
注:解決不同優先級的線程申請鎖的時候不會發生優先級反轉問題.
不過相對於 OSSpinLock , os_unfair_lock性能方面減弱了許多.
*/
三、dispatch_semaphore (信號量)
0.155043s
// 初始化
dispatch_semaphore_t semaphore_t = dispatch_semaphore_create(1);
// 加鎖
dispatch_semaphore_wait(semaphore_t,DISPATCH_TIME_FOREVER);
// 解鎖
dispatch_semaphore_signal(semaphore_t);
/*
注: dispatch_semaphore 其他兩個功能
1.還可以起到阻塞線程的作用.
2.可以實現定時器功能,這里不做過多介紹.
*/
四、pthread_mutex(互斥鎖)
0.262592s
需要導入頭文件
#import <pthread/pthread.h>
// 初始化(兩種)
1.普通初始化
pthread_mutex_t mutex_t;
pthread_mutex_init(&mutex_t, NULL);
2.宏初始化
pthread_mutex_t mutex =PTHREAD_MUTEX_INITIALIZER;
// 加鎖
pthread_mutex_lock(&mutex_t);
// 解鎖
pthread_mutex_unlock(&mutex_t);
// 嘗試加鎖,可以加鎖時返回的是 0,否則返回一個錯誤
pthread_mutex_trylock(& mutex_t)
五、NSLock(互斥鎖、對象鎖)
0.283196s
// 初始化
NSLock *_lock = [[NSLock alloc]init];
// 加鎖
[_lock lock];
// 解鎖
[_lock unlock];
// 嘗試加鎖,可以加鎖則立即加鎖並返回 YES,反之返回 NO
[_lock tryLock];
六、NSCondition(條件鎖、對象鎖)
0.293046s
// 初始化
NSCondition *_condition= [[NSCondition alloc]init];
// 加鎖
[_condition lock];
// 解鎖
[_condition unlock];
/*
其他功能接口
wait 進入等待狀態
waitUntilDate:讓一個線程等待一定的時間
signal 喚醒一個等待的線程
broadcast 喚醒所有等待的線程
注: 所測時間波動太大, 有時候會快於 NSLock, 我取得中間值.
*/
七、NSConditionLock(條件鎖、對象鎖)
0.950285s
// 初始化
NSConditionLock *_conditionLock = [[NSConditionLock alloc]init];
// 加鎖
[_conditionLock lock];
// 解鎖
[_conditionLock unlock];
// 嘗試加鎖,可以加鎖則立即加鎖並返回 YES,反之返回 NO
[_conditionLock tryLock];
/*
其他功能接口
- (instancetype)initWithCondition:(NSInteger)condition NS_DESIGNATED_INITIALIZER; //初始化傳入條件
- (void)lockWhenCondition:(NSInteger)condition;//條件成立觸發鎖
- (BOOL)tryLockWhenCondition:(NSInteger)condition;//嘗試條件成立觸發鎖
- (void)unlockWithCondition:(NSInteger)condition;//條件成立解鎖
- (BOOL)lockBeforeDate:(NSDate *)limit;//觸發鎖 在等待時間之內
- (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit;//觸發鎖 條件成立 並且在等待時間之內
*/
八、NSRecursiveLock(遞歸鎖、對象鎖)
0.473536s
// 初始化
NSRecursiveLock *_recursiveLock = [[NSRecursiveLock alloc]init];
// 加鎖
[_recursiveLock lock];
// 解鎖
[_recursiveLock unlock];
// 嘗試加鎖,可以加鎖則立即加鎖並返回 YES,反之返回 NO
[_recursiveLock tryLock];
/*
注: 遞歸鎖可以被同一線程多次請求,而不會引起死鎖。
即在同一線程中在未解鎖之前還可以上鎖, 執行鎖中的代碼。
這主要是用在循環或遞歸操作中。
- (BOOL)lockBeforeDate:(NSDate *)limit;//觸發鎖 在等待時間之內
*/
九、@synchronized(條件鎖)
1.101924s
// 初始化
@synchronized(條件){
}
十、pthread_mutex(recursive)(遞歸鎖)
0.372398s
// 初始化
pthread_mutex_t mutex_t;
pthread_mutexattr_t attr;
pthread_mutexattr_init(&attr); //初始化attr並且給它賦予默認pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); //設置鎖類型,這邊是設置為遞歸鎖
pthread_mutex_init(&mutex_t, &attr);
pthread_mutexattr_destroy(&attr); //銷毀一個屬性對象,在重新進行初始化之前該結構不能重新使用
// 加鎖
pthread_mutex_lock(&mutex_t);
// 解鎖
pthread_mutex_unlock(&mutex_t);
/*
注: 遞歸鎖可以被同一線程多次請求,而不會引起死鎖。
即在同一線程中在未解鎖之前還可以上鎖, 執行鎖中的代碼。
這主要是用在循環或遞歸操作中。
*/
性能總結
OSSpinLock 0.097348s
dispatch_semaphore 0.155043s
os_unfair_lock 0.171789s
pthread_mutex 0.262592s
NSLock 0.283196s
pthread_mutex(recursive) 0.372398s
NSRecursiveLock 0.473536s
NSConditionLock 0.950285s
@synchronized 1.101924s
注:建議正常鎖功能用 pthread_mutex ,os_unfair_lock (適配低版本)