在 iOS 中毅贮,鎖是多線程編程中的關(guān)鍵要素办悟,也是保證線程安全的重要手段之一。本文將介紹常見的幾種鎖及其使用場景滩褥,并提供相關(guān)的代碼示例病蛉。
iOS中的鎖主要可以分為兩大類,互斥鎖和自旋鎖,其他鎖都是這兩種鎖的延伸和擴展铺然。
一俗孝、自旋鎖
原理
自旋鎖是一種基于忙等待的鎖,當(dāng)多個線程訪問共享資源時魄健,自旋鎖會不停地進行循環(huán)檢查赋铝,直到獲取到鎖為止。自旋鎖的好處在于它避免了線程切換和上下文切換的開銷沽瘦,在多核 CPU 上革骨,自旋鎖可以充分利用 CPU 時間片,因此在鎖競爭不激烈的情況下析恋,自旋鎖的性能比互斥鎖好良哲。
使用場景
自旋鎖適用于以下場景:
- 多個線程訪問共享資源的競爭不激烈,即鎖競爭不激烈助隧。
- 訪問共享資源的時間很短筑凫,即不會發(fā)生線程掛起。
iOS只有一種自旋鎖:OSSpinLock并村,其使用方法如下:
#import <libkern/OSAtomic.h>
OSSpinLock spinLock = OS_SPINLOCK_INIT;
// 獲取鎖
OSSpinLockLock(&spinLock);
// 臨界區(qū)代碼
// 釋放鎖
OSSpinLockUnlock(&spinLock);
需要注意的是京闰,由于自旋鎖等待線程不會進入阻塞狀態(tài)尺碰,而是不斷嘗試獲取鎖啥繁,如果等待時間過長會導(dǎo)致CPU占用過高穷遂,從而影響應(yīng)用程序的性能栖茉。此外鲁豪,OSSpinLock還存在優(yōu)先級反轉(zhuǎn)的問題航背。
優(yōu)先級反轉(zhuǎn)指的是高優(yōu)先級的線程因等待低優(yōu)先級線程所持有的鎖而被阻塞的情況延柠。在這種情況下洗显,高優(yōu)先級的線程可能一直等待外潜,直到低優(yōu)先級的線程釋放鎖。并且高優(yōu)先級的線程會搶占CPU資源挠唆,低優(yōu)先級的線程得不到CPU調(diào)度处窥,進而延長了等待時間,導(dǎo)致高優(yōu)先級的任務(wù)被延遲執(zhí)行玄组。
由于這些原因滔驾,OSSpinLock已被蘋果廢棄。
二俄讹、互斥鎖
互斥鎖是一種常見的鎖哆致,用于保護臨界區(qū)代碼,防止多個線程同時訪問共享資源患膛。
與自旋鎖不同的是摊阀,互斥鎖會將未獲得鎖的線程掛起,等待鎖的釋放。這種操作需要進行上下文切換胞此,開銷較大臣咖,因此互斥鎖的性能不如自旋鎖。
iOS 中的常見互斥鎖包括 pthread_mutex_t漱牵、NSLock夺蛇、NSCondition、NSConditionLock酣胀、NSRecursiveLock等刁赦。
1.pthread_mutex_t
pthread_mutex是一種互斥鎖,它可以保證同一時間只有一個線程可以訪問共享資源灵临。pthread_mutex基于POSIX標(biāo)準(zhǔn)實現(xiàn)截型。
pthread_mutex與其他鎖機制相比,具有以下特點:
- 輕量級儒溉,適合高并發(fā)場景宦焦。
- 由于是C語言的庫,使用起來相對較復(fù)雜顿涣。
代碼示例
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
// 獲取鎖
pthread_mutex_lock(&mutex);
// 臨界區(qū)代碼
// 釋放鎖
pthread_mutex_unlock(&mutex);
2.NSLock
NSLock是一個簡單的互斥鎖波闹,它基于POSIX線程互斥鎖實現(xiàn)。
代碼示例
NSLock *lock = [[NSLock alloc] init];
// 獲取鎖
[lock lock];
// 臨界區(qū)代碼
// 釋放鎖
[lock unlock];
3. NSCondition
NSCondition是一種條件鎖涛碑,它可以讓線程在某個條件滿足時等待精堕,并在條件滿足時喚醒線程。NSCondition基于pthread_cond_t和pthread_mutex_t實現(xiàn)蒲障。
NSCondition適用于以下場景:
- 需要等待某個條件滿足后再進行訪問的場景歹篓。
- 支持多個條件等待和喚醒的場景。
代碼示例
// 初始化條件鎖和條件變量
NSCondition *condition = [[NSCondition alloc] init];
BOOL conditionMet = NO;
- (void)waitExample {
// 等待條件滿足
[condition lock];
while (!conditionMet) {
[condition wait];
}
// 訪問共享資源
// 釋放鎖
[condition unlock];
}
- (void)signalExample {
// 喚醒等待的線程
[condition lock];
conditionMet = YES;
[condition signal];
[condition unlock];
}
4. NSConditionLock
NSConditionLock是一種條件鎖揉阎,它可以讓線程在不同的條件下等待庄撮。NSConditionLock基于NSCondition和一個內(nèi)部的狀態(tài)變量實現(xiàn)。
NSConditionLock與其他鎖機制相比毙籽,具有以下特點:
- 支持多個條件等待和喚醒洞斯。
- 支持在不同的條件下等待。
代碼示例
// 初始化條件鎖
NSConditionLock *conditionLock = [[NSConditionLock alloc] initWithCondition:0];
- (void)conditionLockExample {
// 等待條件1
[conditionLock lockWhenCondition:0];
// 訪問共享資源
// 設(shè)置條件2
[conditionLock unlockWithCondition:1];
// 等待條件2
[conditionLock lockWhenCondition:1];
// 訪問共享資源
// 釋放鎖
[conditionLock unlock];
}
5. NSRecursiveLock
NSRecursiveLock是一種遞歸鎖坑赡,它允許同一個線程多次獲取鎖烙如,避免死鎖。
NSRecursiveLock與其他鎖機制相比毅否,具有以下特點:
- 支持遞歸鎖亚铁,同一線程可以多次獲取同一把鎖,避免死鎖搀突。
- NSRecursiveLock的性能比NSLock略低刀闷,因為它需要維護額外的狀態(tài)以支持遞歸鎖熊泵。
代碼示例
// 初始化遞歸鎖
NSRecursiveLock *recursiveLock = [[NSRecursiveLock alloc] init];
- (void)recursiveLockExample {
// 獲取遞歸鎖
[recursiveLock lock];
// 訪問共享資源
// 再次獲取遞歸鎖
[recursiveLock lock];
// 訪問共享資源
// 釋放遞歸鎖
[recursiveLock unlock];
// 釋放遞歸鎖
[recursiveLock unlock];
}
三. 信號量
原理
信號量是一種常見的并發(fā)控制機制,用于控制對共享資源的訪問甸昏。當(dāng)多個線程訪問共享資源時顽分,信號量可以用來限制并發(fā)訪問的數(shù)量。信號量有一個計數(shù)器施蜜,每個線程訪問共享資源前需要獲取信號量卒蘸,如果計數(shù)器為0,則線程需要等待翻默,直到其他線程釋放信號量為止缸沃。如果計數(shù)器不為0,則線程可以訪問共享資源修械,并將計數(shù)器減1趾牧。當(dāng)線程訪問完共享資源后,需要釋放信號量肯污,使計數(shù)器加1翘单,以便其他線程可以訪問共享資源。
區(qū)別
與互斥鎖和自旋鎖不同的是蹦渣,信號量可以控制對共享資源的并發(fā)訪問數(shù)量哄芜,因此它更適合用于限制并發(fā)度較高的情況。
使用場景
- 多個線程訪問共享資源的競爭激烈柬唯,即鎖競爭激烈认臊。
- 需要控制并發(fā)訪問的數(shù)量。
代碼示例
// 初始化信號量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);
- (void)lockExample {
// 等待信號量
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// 訪問共享資源
// 釋放信號量
dispatch_semaphore_signal(semaphore);
}
總結(jié)
本文介紹了iOS開發(fā)中常見的五種鎖機制:互斥鎖锄奢、自旋鎖失晴、信號量、讀寫鎖和GCD同步鎖拘央。對于每種鎖機制师坎,我們講解了它的原理、區(qū)別堪滨、使用場景和代碼示例,以便開發(fā)者可以根據(jù)實際情況選擇合適的鎖機制來實現(xiàn)多線程訪問控制蕊温。在實際開發(fā)中袱箱,我們需要根據(jù)具體的場景選擇合適的鎖機制,以保證多線程程序的正確性和效率义矛。