iOS 開(kāi)發(fā)做瞪,各種鎖你了解多少对粪?NSLock、NSCondtion装蓬、NSRecursiveLock.......
回顧
在上篇博客中已經(jīng)通過(guò) Swift
的Foundation
源碼分析NSLock
著拭、NSCondtion
、NSRecursiveLock
牍帚、NSCondition
等鎖了儡遮,那么本篇博將手把手帶你實(shí)現(xiàn)一個(gè)讀寫(xiě)鎖
!
iOS底層探索之多線程(五)—GCD不同隊(duì)列源碼分析
iOS底層探索之多線程(六)—GCD源碼分析(sync 同步函數(shù)鄙币、async 異步函數(shù))
iOS底層探索之多線程(八)—GCD源碼分析(函數(shù)的同步性、異步性蹂随、單例)
iOS底層探索之多線程(九)—GCD源碼分析(柵欄函數(shù))
iOS底層探索之多線程(十)—GCD源碼分析( 信號(hào)量)
iOS底層探索之多線程(十一)—GCD源碼分析(調(diào)度組)
iOS底層探索之多線程(十三)—鎖的種類(lèi)你知多少?
iOS底層探索之多線程(十四)—關(guān)于@synchronized鎖你了解多少?
iOS底層探索之多線程(十五)—@synchronized源碼分析
iOS底層探索之多線程(十六)——鎖分析(NSLock十嘿、NSCondtion、NSRecursiveLock岳锁、NSCondition)
iOS底層探索之多線程(十七)——通過(guò) Swift的Foundation源碼分析鎖(NSLock绩衷、NSCondition、NSRecursiveLock)
1. 什么是讀寫(xiě)鎖?
在開(kāi)始之前咳燕,先來(lái)了解一下勿决,什么是
讀寫(xiě)鎖
?
-
讀寫(xiě)鎖
實(shí)際是?種特殊的?旋鎖
招盲,它把對(duì)共享資源的訪問(wèn)者劃分成讀者
和寫(xiě)者
剥险,讀者只對(duì)共享資源進(jìn)?讀訪問(wèn)
,寫(xiě)者則需要對(duì)共享資源進(jìn)?寫(xiě)操作
宪肖。 - 這種鎖相對(duì)于
?旋鎖
??,能提?并發(fā)性健爬,因?yàn)樵诙嗵幚砥飨到y(tǒng)中控乾,它允許同時(shí)有多個(gè)讀者
來(lái)訪問(wèn)共享資源
,最?可能的讀者數(shù)為實(shí)際的邏輯CPU數(shù)
娜遵。 - 寫(xiě)者是
排他性
的蜕衡,?個(gè)讀寫(xiě)鎖同時(shí)只能有?個(gè)寫(xiě)者或多個(gè)讀者(與CPU數(shù)
相關(guān)),但不能同時(shí)既有讀者?有寫(xiě)者设拟,在讀寫(xiě)鎖保持期間也是搶占失效的慨仿。 - 如果
讀寫(xiě)鎖
當(dāng)前沒(méi)有讀者
,也沒(méi)有寫(xiě)者纳胧,那么寫(xiě)者可以?刻獲得
讀寫(xiě)鎖镰吆,否則它必須?旋
在那?,直到?jīng)]有任何寫(xiě)者或讀者跑慕。 - 如果
讀寫(xiě)鎖
沒(méi)有寫(xiě)者
万皿,那么讀者可以?即獲得該讀寫(xiě)鎖,否則讀者必須
?旋在那?核行,直到寫(xiě)者釋放
該讀寫(xiě)鎖牢硅。 - ?次只有?個(gè)線程可以占有
寫(xiě)模式
的讀寫(xiě)鎖, 但是可以有多個(gè)線程同時(shí)
占有讀模式的讀寫(xiě)鎖,正是因?yàn)檫@個(gè)特性芝雪,當(dāng)讀寫(xiě)鎖是寫(xiě)加鎖狀態(tài)時(shí)减余,在這個(gè)鎖被解鎖之前,所有試圖對(duì)這個(gè)鎖加鎖的線程都會(huì)被阻塞
惩系。 - 當(dāng)讀寫(xiě)鎖在
讀加鎖狀態(tài)
時(shí)位岔,所有試圖以讀模式對(duì)它進(jìn)?加鎖的線程都可以得到訪問(wèn)權(quán)
,但是如果線程
希望以寫(xiě)模式對(duì)此鎖進(jìn)?加鎖
蛆挫, 它必須直到所有的線程釋放鎖
赃承。 - 通常的情況是當(dāng)
讀寫(xiě)鎖
處于讀模式鎖住狀態(tài)
時(shí),如果有另外線程試圖
以寫(xiě)模式加鎖悴侵,讀寫(xiě)鎖通常會(huì)阻塞
隨后的讀模式鎖請(qǐng)求瞧剖,這樣可以避免讀模式鎖?期占?
,?等待的寫(xiě)模式鎖請(qǐng)求?期阻塞
。 -
讀寫(xiě)鎖
適合于對(duì)數(shù)據(jù)結(jié)構(gòu)的讀次數(shù)?寫(xiě)次數(shù)多得多的情況抓于。 因?yàn)? 讀模式鎖定時(shí)可以共享做粤, 以寫(xiě)模式鎖住時(shí)意味著獨(dú)占,所以讀寫(xiě)鎖?叫共享-獨(dú)占鎖
捉撮。
那我們?cè)撊绻?code>封裝實(shí)現(xiàn)一個(gè)
讀寫(xiě)鎖
呢怕品?
首先我們要明白讀寫(xiě)鎖的核心功能
是什么?毫無(wú)疑問(wèn)肯定是:多讀單寫(xiě)
巾遭。
-
多讀
就是允許多條線程對(duì)這個(gè)內(nèi)存空間進(jìn)行讀取操作肉康。 -
單寫(xiě)
就是同一時(shí)刻只能有一個(gè)線程,對(duì)這一片內(nèi)存空間進(jìn)行寫(xiě)操作灼舍,如果有多個(gè)寫(xiě)操作吼和,數(shù)據(jù)肯定就錯(cuò)亂了,這是我們所不能允許的骑素。 -
寫(xiě)與寫(xiě)要互斥
:炫乓,A寫(xiě)完了,B才能進(jìn)行寫(xiě)献丑。 -
讀與寫(xiě)要互斥
:A在寫(xiě)的時(shí)候末捣,B不能讀,必須要等 A寫(xiě)完B再去讀创橄。 - 讀寫(xiě)不能堵塞主線程箩做,不能影響正常的程序運(yùn)行。
既然所有的注意點(diǎn)和功能點(diǎn)都清楚了妥畏,那么廢話不多少卒茬,開(kāi)工吧!這里將通過(guò)兩種方式進(jìn)行實(shí)現(xiàn)分別是
pthread
的API
和GCD
的API
咖熟。
2. pthread 實(shí)現(xiàn)讀寫(xiě)鎖
那么首先圃酵,我們先使用pthread
來(lái)實(shí)現(xiàn)一下,模擬火車(chē)票的情況馍管,代碼如下:
//注意這里要導(dǎo)入頭文件
#import <pthread.h>
@interface ViewController ()
@property (nonatomic, assign) NSUInteger trainTickets;//火車(chē)票數(shù)量
@property (nonatomic, assign) pthread_rwlock_t jpLock;// 鎖
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.trainTickets = 0;
[self jp_Test];
}
- 讀操作
// 讀方法
-(void)jP_read{
// 讀加鎖
pthread_rwlock_rdlock(&_jpLock);
sleep(1);
NSLog(@"讀取火車(chē)票數(shù)量為:%zd", self.trainTickets);
// 解鎖
pthread_rwlock_unlock(&_jpLock);
}
- 寫(xiě)操作
// 寫(xiě)方法
-(void)jP_write{
// 寫(xiě)加鎖
pthread_rwlock_wrlock(&_jpLock);
sleep(1);
NSLog(@"寫(xiě)入后火車(chē)票數(shù)量為:%zd", ++self.trainTickets);
// 解鎖
pthread_rwlock_unlock(&_jpLock);
}
- 來(lái)看看運(yùn)行結(jié)果如何
代碼完美運(yùn)行郭赐,非常完美!結(jié)果很正常确沸,沒(méi)有錯(cuò)亂捌锭!
pthread API
pthread_rwlock_t lock;
// 結(jié)構(gòu)pthread_rwlock_init(&lock, null);
// 初始化pthread_rwlock_rdlock(&lock);
// 讀加鎖pthread_rwlock_tryrdlock(&lock);
// 讀嘗試加鎖pthread_rwlock_wdlock(&lock);
// 寫(xiě)加鎖pthread_rwlock_trywdlock(&lock);
// 寫(xiě)嘗試加鎖pthread_rwlock_unlock(&lock);
// 解鎖pthread_rwlock_destory(&lock);
// 銷(xiāo)毀
3. GCD 實(shí)現(xiàn)讀寫(xiě)鎖
上面??已經(jīng)用pthread
實(shí)現(xiàn)了讀寫(xiě)鎖
罗捎,那么現(xiàn)在就用我們比較熟悉的 GCD
來(lái)實(shí)現(xiàn)一下吧观谦!
-
GCD實(shí)現(xiàn)代碼如下:
GCD實(shí)現(xiàn)代碼 - GCD實(shí)現(xiàn)運(yùn)行結(jié)果如下:
結(jié)果和上面用
pthread
實(shí)現(xiàn)的效果是一樣的,這里就不過(guò)多分析了桨菜,代碼注釋都有豁状,相信大家都懂的捉偏!
4. 總結(jié)
- 讀寫(xiě)鎖的核心功能就是
多讀單寫(xiě)
- 寫(xiě)與寫(xiě)要互斥
- 讀與寫(xiě)要互斥
- 讀寫(xiě)
不能堵塞主線程
泻红,不能影響正常的程序運(yùn)行夭禽。
更多內(nèi)容持續(xù)更新
?? 喜歡就點(diǎn)個(gè)贊吧????
?? 覺(jué)得有收獲的,可以來(lái)一波谊路,收藏+關(guān)注讹躯,評(píng)論 + 轉(zhuǎn)發(fā),以免你下次找不到我????
??歡迎大家留言交流缠劝,批評(píng)指正潮梯,互相學(xué)習(xí)??,提升自我??