iOS多线程与锁
多線程方案
pthread:一套C語言通用多線程API,跨平臺,使用難度較大,需要開發者管理生命周期,iOS中幾乎用不到
NSThread:基于pthread的封裝,面向對象,同樣需要開發者管理生命周期,iOS中偶爾使用
GCD:能充分利用設備多核,提高效率,C語言API,自動管理生命周期,iOS經常使用
NSOperation:基于GCD的封裝,使用更加面向對象,OC語言,自動管理生命周期,iOS經常使用
以上方案的使用方法,這里不展開做介紹,本篇文章主要回顧iOS中鎖相關知識。
多線程安全隱患
當多個線程訪問同一塊資源時,容易引發數據安全問題。常見的場景:銀行存取錢的計算,多窗口售票等等,都映射到多線程的安全隱患。
舉個例子:
當整型17被線程A和線程B先后讀取并進行了+1操作,理論上最后得到的結果應該是19,因為進行了兩次+1,但是結果就出現了異常,這就是數據錯亂。解決方案就是使用線程同步技術,給定先后次序進行操作,常見的線程同步技術就是加鎖。
加鎖后保證僅有一條線程對17進行讀和寫,待線程操作完成解鎖后后面線程才可進行讀寫操作,這樣一來得到的數據就正確了。
線程同步方案
OSSpinLock:自旋鎖,等待鎖的線程會處于忙等狀態,一直占用CPU資源,目前已經不再安全,可能會出現優先級反轉問題。
os_unfair_lock:用于取代不安全的OSSpinLock,iOS10開始支持,并且等待os_unfair_lock鎖的線程會處于休眠狀態,而不是忙等狀態,一定程度上節省CPU資源,使用需要導入<os/lock.h>
pthread_mutex:互斥鎖,等待鎖的線程會處于休眠狀態,需導入<pthread.h>
普通鎖:
遞歸鎖:
條件鎖:
NSLock:是對mutex普通鎖的封裝,使用更加面向對象
NSRecursiveLock:是對mutex遞歸鎖的封裝,API與NSLock基本一致
NSCondition:是對mutex和cond的封裝
NSConditionLock:是對NSCondition的進一步封裝
@interface NSConditionLock : NSObject <NSLocking> { @privatevoid *_priv; } - (instancetype)initWithCondition:(NSInteger)condition; @property (readonly) NSInteger condition; - (void)lockWhenCondition:(NSInteger)condition; - (BOOL)tryLock; - (BOOL)tryLockWhenCondition:(NSInteger)condition; - (void)unlockWithCondition:(NSInteger)condition; - (BOOL)lockBeforeDate:(NSDate *)limit; - (BOOL)lockWhenCondition:(NSInteger)condition beforeDate:(NSDate *)limit; @property (nullable, copy) NSString *name; @enddispatch_semaphore:信號量,可以控制并發訪問最大數量,信號量初始化值為1代表同時只能有1條線程訪問資源用于確保線程同步。
//信號量初始值 int value = 1 //初始化信號量 dispatch_semaphore_t semaphore = dispatch_semaphore_create(value); //如果信號量值<=0,當前線程就會進入休眠等待,直到信號量>0 //如果當前信號量>0 就減1,然后執行后面代碼 dispatch_semphore_wait(semaphore,DISPATCH_TIME_FOREVER) //讓信號量值+1 dispatch_semphore_signal(semaphore)@synchronized:是對mutex封裝,@synchronized(obj)內部生成obj對應的遞歸鎖,然后進行加鎖解鎖操作。
自旋鎖和互斥鎖的比較
什么情況下使用自旋鎖:
1、預計線程等待鎖的時間很短
2、多核處理器
3、CPU資源不緊張
4、加鎖的代碼(臨界區)經常被調用,但是很少出現競爭資源情況
什么情況下使用互斥鎖:
1、預計線程等待鎖的時間比較長
2、單核處理器
3、臨界區有IO操作
4、臨界區競爭非常激烈
5、臨界區代碼復雜或者循環量大
總結
- 上一篇: 揭秘天猫双11背后:20万商家600万张
- 下一篇: IT企业专利工程师之三——计算机技术领域