1基本概念
線程(線程)用于指代獨(dú)立執(zhí)行的代碼段瞒渠。
進(jìn)程(process)用于指代一個(gè)正在運(yùn)行的可執(zhí)行程序,它可以包含多個(gè)線程。?
?任務(wù)(task)用于指代抽象的概念,表示需要執(zhí)行工作舟扎。
多線程讓應(yīng)用程序內(nèi)擁有多個(gè)可執(zhí)行路徑,會(huì)給你的代碼增加更多的復(fù)雜性。每個(gè) 線程需要和其他線程協(xié)調(diào)其行為,以防止它破壞應(yīng)用程序的狀態(tài)信息悴务。因?yàn)閼?yīng)用程序 內(nèi)的多個(gè)線程共享內(nèi)存空間,它們?cè)L問(wèn)相同的數(shù)據(jù)結(jié)構(gòu)睹限。如果兩個(gè)線程試圖同時(shí)處理 相同的數(shù)據(jù)結(jié)構(gòu),一個(gè)線程有可能覆蓋另外線程的改動(dòng)導(dǎo)致破壞該數(shù)據(jù)結(jié)構(gòu)。即使有 適當(dāng)?shù)谋Wo(hù),你仍然要注意由于編譯器的優(yōu)化導(dǎo)致給你代碼產(chǎn)生的微妙影響讯檐。
線程啟動(dòng)之后,線 程就進(jìn)入三個(gè)狀態(tài)中的任何一個(gè):運(yùn)行(running)羡疗、就緒(ready)、阻塞(blocked)别洪。如 果一個(gè)線程當(dāng)前沒(méi)有運(yùn)行,那么它不是處于阻塞,就是等待外部輸入,或者已經(jīng)準(zhǔn)備 就緒等待分配 CPU叨恨。線程持續(xù)在這三個(gè)狀態(tài)之間切換,直到它最終退出或者進(jìn)入中斷 狀態(tài)。
當(dāng)你顯式的中斷線程的時(shí)候,線程永久停止,且被系統(tǒng)回收蕉拢。因?yàn)榫€程創(chuàng)建需 要的內(nèi)存和時(shí)間消耗都比較大,因此建議你的入口點(diǎn)函數(shù)做相當(dāng)數(shù)量的工作,或建立 一個(gè)運(yùn)行循環(huán)允許進(jìn)行經(jīng)常性的工作特碳。
Run Loops (運(yùn)行 循環(huán) )
為了配置 run loop,你所需要做的是啟動(dòng)你的線程,獲取 run loop 的對(duì)象引用, 設(shè)置你的事件處理程序,并告訴 run loop 運(yùn)行诚亚。Cocoa 和 Carbon 提供的基礎(chǔ)設(shè)施會(huì) 自動(dòng)為你的主線程配置相應(yīng)的 run loop。如果你打算創(chuàng)建長(zhǎng)時(shí)間運(yùn)行的輔助線程, 那么你必須為你的線程配置相應(yīng)的 run loop午乓。
同步工具
線程編程的危害之一是在多個(gè)線程之間的資源爭(zhēng)奪站宗。如果多個(gè)線程在同一個(gè)時(shí)間 試圖使用或者修改同一個(gè)資源,就會(huì)出現(xiàn)問(wèn)題。緩解該問(wèn)題的方法之一是消除共享資 源,并確保每個(gè)線程都有在它操作的資源上面的獨(dú)特設(shè)置益愈。因?yàn)楸3滞耆?dú)立的資源 是不可行的,所以你可能必須使用鎖,條件,原子操作和其他技術(shù)來(lái)同步資源的訪問(wèn)
鎖
鎖提供了一次只有一個(gè)線程可以執(zhí)行代碼的有效保護(hù)形式梢灭。最普遍的一種鎖是互 斥排他鎖,也就是我們通常所說(shuō)的“mutex”。
除了鎖,系統(tǒng)還提供了條件,確保在你的應(yīng)用程序任務(wù)執(zhí)行的適當(dāng)順序蒸其。一個(gè)條 件作為一個(gè)看門人,阻塞給定的線程,直到它代表的條件變?yōu)檎婷羰汀.?dāng)發(fā)生這種情況的 時(shí)候,條件釋放該線程并允許它繼續(xù)執(zhí)行
盡管鎖和條件在并發(fā)設(shè)計(jì)中使用非常普遍,原子操作也是另外一種保護(hù)和同步訪 問(wèn)數(shù)據(jù)的方法。原子操作在以下情況的時(shí)候提供了替代鎖的輕量級(jí)的方法,其中你可 以執(zhí)行標(biāo)量數(shù)據(jù)類型的數(shù)學(xué)或邏輯運(yùn)算
線程間通信
雖然一個(gè)良好的設(shè)計(jì)最大限度地減少所需的通信量,但在某些時(shí)候,線程之間的 通信顯得十分必要摸袁。
線程可能需要處理新的工作要求,或向你應(yīng)用程 序的主線程報(bào)告其進(jìn)度情況钥顽。在這些情況下,你需要一個(gè)方式來(lái)從其他線程獲取信息。 幸運(yùn)的是,線程共享相同的進(jìn)程空間,意味著你可以有大量的可選項(xiàng)來(lái)進(jìn)行通信靠汁,“配置線程局部存儲(chǔ)”蜂大。
2設(shè)計(jì)技巧
避免顯式創(chuàng)建線程
比如 GCD 和操作對(duì)象技術(shù)被設(shè)計(jì)用來(lái)管 理線程,比通過(guò)自己的代碼根據(jù)當(dāng)前的負(fù)載調(diào)整活動(dòng)線程的數(shù)量更高效
避免共享數(shù)據(jù)結(jié)構(gòu)
避免造成線程相關(guān)資源沖突的最簡(jiǎn)單最容易的辦法是給你應(yīng)用程序的每個(gè)線程一份它需求的數(shù)據(jù)的副本。
主線程刷新你的UI界面
主線程里面接收和界面相關(guān)的事件和初始化更新你的界面
3線程管理(考慮線程成本)
創(chuàng)建一個(gè)線程
使用NSThread
設(shè)置線程的優(yōu)先級(jí)
4Run Loops
5線程同步
同步工具:1原子操作 2鎖 3條件
線程安全設(shè)計(jì)的技巧:
1完全避免同步:實(shí)現(xiàn)并發(fā)最好的方法是減少你并發(fā)任務(wù)之間的交互和相互依賴蝶怔。如果每個(gè)任務(wù)在它自己的數(shù)據(jù)集上面操作,那它不需要使用鎖來(lái)保護(hù)這些數(shù)據(jù)奶浦。甚至如果兩個(gè)任務(wù)共享一個(gè)普通數(shù)據(jù)集,你可以查看分區(qū)方法,它們?cè)O(shè)置或提供拷貝每一項(xiàng)任務(wù)的方法。當(dāng)然,拷貝數(shù)據(jù)集本身也需要成本,所以在你做出決定前,你需要權(quán)衡這些成本和使用同步工具造成的成本那個(gè)更可以接受踢星。
當(dāng)心死鎖(Deadlocks)和活鎖(Livelocks):
任何時(shí)候線程試圖同時(shí)獲得多于一個(gè)鎖,都有可能引發(fā)潛在的死鎖澳叉。當(dāng)兩個(gè)不同的線程分別保持一個(gè)鎖(而該鎖是另外一個(gè)線程需要的)又試圖獲得另外線程保持的鎖時(shí)就會(huì)發(fā)生死鎖。結(jié)果是每個(gè)線程都會(huì)進(jìn)入持久性阻塞狀態(tài),因?yàn)樗肋h(yuǎn)不可能獲得另外那個(gè)鎖沐悦。
一個(gè)活鎖和死鎖類似,當(dāng)兩個(gè)線程競(jìng)爭(zhēng)同一個(gè)資源的時(shí)候就可能發(fā)生活鎖成洗。在發(fā)生活鎖的情況里,一個(gè)線程放棄它的第一個(gè)鎖并試圖獲得第二個(gè)鎖。一旦它獲得第二個(gè)鎖,它返回并試圖再次獲得一個(gè)鎖所踊。線程就會(huì)被鎖起來(lái),因?yàn)樗ㄙM(fèi)所有的時(shí)間來(lái)釋放一個(gè)鎖,并試圖獲取其他鎖,而不做實(shí)際的工作泌枪。
避免死鎖和活鎖的最好方法是同一個(gè)時(shí)間只擁有一個(gè)鎖。如果你必須在同一時(shí)間獲取多于一個(gè)鎖,你應(yīng)該確保其他線程沒(méi)有做類似的事情秕岛。
使用原子操作:
獲取一個(gè)鎖是一個(gè)很昂貴的操作,即使在無(wú)競(jìng)爭(zhēng)的狀態(tài)下碌燕。相比,許多原子操作花費(fèi)很少的時(shí)間來(lái)完成操作也可以達(dá)到和鎖一樣的效果。
使用鎖:
1使用POSIX互斥鎖:為了新建一個(gè)互斥鎖,你聲明并初始化一個(gè)pthread_mutex_t的結(jié)構(gòu)继薛。為了鎖住和解鎖一個(gè)互斥鎖,你可以使用pthread_mutex_lock和pthread_mutex_unlock函數(shù)修壕。
2使用NSLock類:
3使用@synchronized指令
4使用NSRecursiveLock對(duì)象
5使用NSConditionLock對(duì)象
6使用NSDistributedLock對(duì)象
使用條件
1使用NSCondition類
2使用POSIX條件