線程的不安全是由于多線程訪問和修改共享資源而引起的不可預(yù)測的結(jié)果。

創(chuàng)新互聯(lián)一直通過網(wǎng)站建設(shè)和網(wǎng)站營銷幫助企業(yè)獲得更多客戶資源。 以"深度挖掘,量身打造,注重實效"的一站式服務(wù),以做網(wǎng)站、網(wǎng)站制作、移動互聯(lián)產(chǎn)品、營銷型網(wǎng)站建設(shè)服務(wù)為核心業(yè)務(wù)。十載網(wǎng)站制作的經(jīng)驗,使用新網(wǎng)站建設(shè)技術(shù),全新開發(fā)出的標(biāo)準(zhǔn)網(wǎng)站,不但價格便宜而且實用、靈活,特別適合中小公司網(wǎng)站制作。網(wǎng)站管理系統(tǒng)簡單易用,維護(hù)方便,您可以完全操作網(wǎng)站資料,是中小公司快速網(wǎng)站建設(shè)的選擇。
ios多線程開發(fā)中為保證線程的安全常用到的幾種鎖: NSLock 、 dispatch_semaphore 、 NSCondition 、 NSRecursiveLock 、 @synchronized 。
WEAKSELF typeof(self) __weak weakSelf = self;
NSLock 是OC層封裝底層線程操作來實現(xiàn)的一種鎖,繼承NSLocking協(xié)議。不能迭代加鎖,如果發(fā)生兩次lock,而未unlock過,則會產(chǎn)生死鎖問題。
以車站購票為例,多個窗口同時售票(同步),每個窗口有人循環(huán)購票:
原子操作
原子操作是指不可打斷的操作,也就是說線程在執(zhí)行操作的過程中,不會被操作系統(tǒng)掛起,而是一定會執(zhí)行完,
變量屬性Property中的原子定義
一般我們定義一個變量@property (nonatomic ,strong)NSLock *lock;nonatomic:非原子性,不會為setter方法加鎖,適合內(nèi)存小的移動設(shè)備;atomic:原子性,默認(rèn)為setter方法加鎖(默認(rèn)就是atomic),線程安全。
PS: 在iOS開發(fā)過程中,一般都將屬性聲明為nonatomic,盡量避免多線程搶奪同一資源,盡量將加鎖等資源搶奪業(yè)務(wù)交給服務(wù)器。
NSCondition常用于生產(chǎn)者-消費者模式,它繼承了NSLocking協(xié)議,同樣有l(wèi)ock和unlock方法。條件變量有點像信號量,提供了線程阻塞和信號機制,因此可以用來阻塞某個線程,并等待數(shù)據(jù)就緒再喚醒程序。
信號量主要有3個函數(shù),分別是:
注意: 正常的使用順序是先降低然后提高,這兩個函數(shù)通常都是成對出現(xiàn)。
本文主要參考了這篇文章(
),并對其中所能理解的部分進(jìn)行一一驗證,以前沒怎么寫過類似的,如果有什么做的不好的地方還請大家多多見諒!
要保證線程安全,就必須要線程同步,而在iOS中線程同步的方案有:
在 iOS 中,原子操作可以保證屬性在單獨的 setter 或者 getter 方法中是線程安全的,但是不能保證多個線程對同一個屬性進(jìn)行讀寫操作時,可以得到預(yù)期的值,也就是原子操作不保證線程安全,例如:
在 Objective-C 中,可以在設(shè)置屬性的時候,使用 atomic 來設(shè)置原子屬性,保證屬性 setter 、 getter 的原子性操作,底層是在 getter 和 setter 內(nèi)部使用 os_unfair_lock 加鎖
在 Swift 中,原生沒有提供原子操作,可以使用 DispatchQueue 的同步函數(shù)來達(dá)到同樣的效果
pthread 表示 POSIX thread ,是 POSIX 標(biāo)準(zhǔn)的 unix 多線程庫,定義了一組跨平臺的線程相關(guān)的API。 pthread_mutex 是一種用 C 語言實現(xiàn)的互斥鎖,有單一的擁有者
遞歸鎖是一種特殊互斥鎖。遞歸鎖允許單個線程在釋放之前多次獲取鎖,其他線程保持睡眠狀態(tài),直到鎖的所有者釋放鎖的次數(shù)與獲取它的次數(shù)相同。遞歸鎖主要在遞歸迭代中使用,但也可能在多個方法需要單獨獲取鎖的情況下使用。
pthread_mutex 支持遞歸鎖,只要把 attr 的類型改成 PTHREAD_MUTEX_RECURSIVE 即可,它有單一的擁有者
NSRecursiveLock 是以 Objective-C 對象的形式對 pthread_mutex(Recursive) 的封裝,它有單一的擁有者
條件鎖是一種特殊互斥鎖,需要條件變量(condition variable) 來配合。條件變量有點像信號量,提供了線程阻塞與信號機制,因此可以用來阻塞某個線程,并等待某個數(shù)據(jù)就緒,隨后喚醒線程。條件鎖是為了解決 生產(chǎn)者-消費者模型
pthread_mutex 配合 pthread_cond_t ,可以實現(xiàn)條件鎖,其中 pthread_cond_t 沒有擁有者
NSCondition 是以 Objective-C 對象的形式對 pthread_mutex 和 pthread_cond_t 進(jìn)行了封裝, NSCondition 沒有擁有者
NSConditionLock 是對 NSCondition 的進(jìn)一步封裝,可以設(shè)置條件變量的值。通過改變條件變量的值,可以使任務(wù)之間產(chǎn)生依賴關(guān)系,達(dá)到使任務(wù)按照一定的順序執(zhí)行,它有單一的擁有者(不確定)
讀寫鎖是一種特殊互斥鎖,提供"多讀單寫"的功能,多個線程可以同時對共享資源進(jìn)行讀取,但是同一時間只能有一條線程對共享資源進(jìn)行寫入
pthread_rwlock 有多個擁有者
性能從高到底分別是:
總結(jié):
蘋果官方文檔
白夜追兇,揭開iOS鎖的秘密
起底多線程同步鎖(iOS)
深入理解 iOS 開發(fā)中的鎖
1.進(jìn)程?
具有一定獨立功能的程序關(guān)于某次數(shù)據(jù)集合的一次運行活動,他是操作系統(tǒng)分配資源的基本單位。
進(jìn)程是指系統(tǒng)正在運行的一個應(yīng)用程序,就是一段程序的執(zhí)行過程。
各進(jìn)程之間相互獨立,每個進(jìn)程都運行在受保護(hù)的內(nèi)存空間內(nèi),擁有獨立運行所需的全部資源。
2. 線程
進(jìn)程的最小執(zhí)行單元。線程是一個進(jìn)程的實體。
一個進(jìn)程要想執(zhí)行任務(wù),就必須至少又一個線程,當(dāng)程序啟動時,系統(tǒng)默認(rèn)開啟一條線程,也就是主線程。
3、 進(jìn)程與線程的關(guān)系
線程是進(jìn)程的執(zhí)行單元,進(jìn)程的所有任務(wù)都在線程中執(zhí)行
線程是CPU分配和執(zhí)行任務(wù)的最小單元
一個程序可以有多進(jìn)程,一個進(jìn)程可以有多線程 ,但是一個進(jìn)程至少有一個線程
同一個進(jìn)程內(nèi)的線程共享進(jìn)程內(nèi)的資源
4 多線程原理
同一時間內(nèi)單核CPU 只執(zhí)行一個線程,多線程是CPU 在單位時間內(nèi)在多個線程之間切換,造成多個線程被同時執(zhí)行的假象。
多核CPU 就可以執(zhí)行多個線程
多線程的目的是同步執(zhí)行多個線程,來提高運行效率
5、多線程的優(yōu)缺點
有點:提高執(zhí)行效率 能夠提高CPU的使用率
缺點:占用一定的系統(tǒng)內(nèi)存空間? 線程越多 CPU 調(diào)度線程的開銷越大 程序設(shè)計復(fù)雜(線程之間的通信 數(shù)據(jù)共享)
6、多線程并發(fā) 與并行區(qū)別
并發(fā):在一條線程上快速切換?
并行: 利用多核CPU ,多線程同時進(jìn)行
7、IOS 中的多線程
NSThread 需要手動創(chuàng)建 不需要銷毀 子線程通信很難
GCD?c語言,充分利用了設(shè)備的多核,自動管理線程生命周期。比NSOperation效率更高。
NSOperation??基于gcd封裝,更加面向?qū)ο螅萭cd多了一些功能。
8、多個網(wǎng)絡(luò)請求如何執(zhí)行下一步
使用GCD的dispatch_group_t??
創(chuàng)建一個dispatch_group_t
每次網(wǎng)絡(luò)請求前先dispatch_group_enter,請求回調(diào)后再dispatch_group_leave,enter和leave必須配合使用,有幾次enter就要有幾次leave,否則group會一直存在。
當(dāng)所有enter的block都leave后,會執(zhí)行dispatch_group_notify的block。
NSString *str = @"";
NSURL*url = [NSURLURLWithString:str];
NSURLRequest*request = [NSURLRequestrequestWithURL:url];
NSURLSession *session = [NSURLSession sharedSession];
dispatch_group_tdownloadGroup =dispatch_group_create();
for ( int i=0; i10; i++) {
? ? dispatch_group_enter(downloadGroup);
? ? NSURLSessionDataTask*task = [sessiondataTaskWithRequest:requestcompletionHandler:^(NSData* _Nullable data,NSURLResponse* _Nullable response,NSError* _Nullable error) {
? ? ? ? NSLog(@"%d---%d",i,i);
? ? ? ? dispatch_group_leave(downloadGroup);
? ? }];
? ? [taskresume];
}
dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
? ? NSLog(@"end");
});
7.多個網(wǎng)絡(luò)請求順序執(zhí)行后如何執(zhí)行下一步?
使用信號量semaphore
每一次遍歷,都讓其dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER),這個時候線程會等待,阻塞當(dāng)前線程,直到dispatch_semaphore_signal(sem)調(diào)用之后
NSString*str=@"";
NSURL*url=[NSURL URLWithString:str];
NSURLRequest*request=[NSURLRequest requestWithURL:url];
NSURLSession*session=[NSURLSession sharedSession];
dispatch_semaphore_t sem=dispatch_semaphore_create(0);
for(inti=0;i10;i++){
NSURLSessionDataTask*task=[session dataTaskWithRequest:request completionHandler:^(NSData*_Nullable data,NSURLResponse*_Nullable response,NSError*_Nullable error){
NSLog(@"%d---%d",i,i);
dispatch_semaphore_signal(sem);
}];
[task resume];
dispatch_semaphore_wait(sem,DISPATCH_TIME_FOREVER);
}
dispatch_async(dispatch_get_main_queue(),^{
NSLog(@"end");
});
線程和進(jìn)程在我們開發(fā)中,跟我們一直形影不離,那么什么是進(jìn)程,什么是線程,它們又有什么關(guān)系,這篇文章將為您簡單介紹。
線程概念
進(jìn)程概念
地址空間:同?進(jìn)程的線程共享本進(jìn)程的地址空間( TLS是本地的線程棧存空間,線程的局部空間是某些操作系統(tǒng)為線程提供的私有空間,只具備有限的容量,并不屬于線程,由操作系統(tǒng)單獨安排的 ),?進(jìn)程之間則是獨?的地址空間。
資源擁有:同?進(jìn)程內(nèi)的線程共享本進(jìn)程的資源如內(nèi)存、I/O、cpu等,但是進(jìn)程之間的資源是獨?的。
優(yōu)點:
缺點:
時間?的概念:CPU在多個任務(wù)直接進(jìn)?快速的切換,這個時間間隔就是時間?。
多線程同時執(zhí)行
如果線程非常多
互斥鎖?結(jié)
互斥鎖參數(shù)
nonatomic?原?屬性
atomic原?屬性(線程安全),針對多線程設(shè)計的,默認(rèn)值,保證同?時間只有?個線程能夠?qū)?(但是同?個時間多個線程都可以取值)
atomic本身就有?把鎖(?旋鎖)
單寫多讀:單個線程寫?,多個線程可以讀取
atomic:線程安全,需要消耗?量的資源
nonatomic:?線程安全,適合內(nèi)存?的移動設(shè)備
iOS開發(fā)建議
所有屬性都聲明為nonatomic
盡量避免多線程搶奪同一塊資源
盡量將加鎖,資源搶奪的業(yè)務(wù)邏輯交給服務(wù)器處理,減少APP的壓力
這篇文章簡單介紹了線程與進(jìn)程的概念,煩請大家不吝賜教。
在多線程開發(fā)中,我們常用到GCD,這里探討一下GCD任務(wù)的取消:
1.在iOS 8以后,系統(tǒng)給我們提供了這樣的取消函數(shù) dispatch_block_cancel,不過這個也只能用于dispatch_block_create創(chuàng)建的dispatch_block_t,我們試驗一下:
這時肯定是任務(wù)都會執(zhí)行的
接下來,把注釋的那一行 dispatch_block_cancel(block1);打開,看看效果:
我們發(fā)現(xiàn)block1確實被取消掉了。這是dispatch_block_cancel的用法。
2.很多時候,我們的場景不會去用dispatch_block_create創(chuàng)建dispatch_block_t,這個時候我們?nèi)粝肴∠粋€任務(wù),可以考慮用一個條件來做,滿足條件則執(zhí)行此任務(wù),不滿足則不執(zhí)行,舉個例子:
效果如下:
寫到這里,這兒其實還隱藏了一個知識點,就是block的變量捕獲,有興趣或是不理解的朋友可以研究一下。(如下,為何輸出不是20而是10)
3.過渡到NSOperation
NSOperation是對GCD的封裝,底層也是GCD。
NSOperation給我們封裝了更多的api,這是我在Xcode中提出來的:
我們可以發(fā)現(xiàn)它有狀態(tài)屬性,有取消方法,也有添加依賴方法等...這里我們還是先說取消吧,下面來給大家寫個demo:
這時輸出是:
因為正在執(zhí)行的任務(wù),NSOperation也是不能取消的,所以也是需要將cancel在start前調(diào)用的(就如同滿足一個條件是否需要cancel一樣,也可以滿足條件不調(diào)用start)
本文名稱:ios開發(fā)多線程,ios開發(fā)多線程面試題
轉(zhuǎn)載來于:http://chinadenli.net/article17/dsejpgj.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供網(wǎng)站收錄、、網(wǎng)站導(dǎo)航、面包屑導(dǎo)航、標(biāo)簽優(yōu)化、Google
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)