--ObjC.cn 并發(fā)編程摘要
線程
線程(thread)是組成進程的子單元,操作系統(tǒng)的調(diào)度器可以對線程進行單獨的調(diào)度。
多線程可以在單核 CPU 上同時(或者至少看作同時)運行。操作系統(tǒng)將小的時間片分配給每一個線程,這樣就能夠讓用戶感覺到有多個任務(wù)在同時進行。如果 CPU 是多核的,那么線程就可以真正的以并發(fā)方式被執(zhí)行,從而減少了完成某項操作所需要的總時間。
直接使用線程可能會引發(fā)的一個問題是,如果你的代碼和所基于的框架代碼都創(chuàng)建自己的線程時,那么活動的線程數(shù)量有可能以指數(shù)級增長。這在大型工程中是一個常見問題。例如,在 8 核 CPU 中,你創(chuàng)建了 8 個線程來完全發(fā)揮 CPU 性能。然而在這些線程中你的代碼所調(diào)用的框架代碼也做了同樣事情(因為它并不知道你已經(jīng)創(chuàng)建的這些線程),這樣會很快產(chǎn)生成成百上千的線程。代碼的每個部分自身都沒有問題,然而最后卻還是導(dǎo)致了問題。使用線程并不是沒有代價的,每個線程都會消耗一些內(nèi)存和內(nèi)核資源。
Grand Central Dispatch
通過 GCD,開發(fā)者不用再直接跟線程打交道了,只需要向隊列中添加代碼塊即可,GCD 在后端管理著一個線程池。GCD 不僅決定著你的代碼塊將在哪個線程被執(zhí)行,它還根據(jù)可用的系統(tǒng)資源對這些線程進行管理。這樣可以將開發(fā)者從線程管理的工作中解放出來,通過集中的管理線程,來緩解大量線程被創(chuàng)建的問題。
GCD 公開有 5 個不同的隊列:運行在主線程中的 main queue,3 個不同優(yōu)先級的后臺隊列,以及一個優(yōu)先級更低的后臺隊列(用于 I/O)。 另外,開發(fā)者可以創(chuàng)建自定義隊列:串行或者并行隊列。自定義隊列非常強大,在自定義隊列中被調(diào)度的所有 block 最終都將被放入到系統(tǒng)的全局隊列中和線程池中。
強烈建議,在絕大多數(shù)情況下使用默認的優(yōu)先級隊列就可以了。如果執(zhí)行的任務(wù)需要訪問一些共享的資源,那么在不同優(yōu)先級的隊列中調(diào)度這些任務(wù)很快就會造成不可預(yù)期的行為。這樣可能會引起程序的完全掛起,因為低優(yōu)先級的任務(wù)阻塞了高優(yōu)先級任務(wù),使它不能被執(zhí)行。
互斥鎖
互斥訪問的意思就是同一時刻,只允許一個線程訪問某個特定資源。為了保證這一點,每個希望訪問共享資源的線程,首先需要獲得一個共享資源的互斥鎖,一旦某個線程對資源完成了操作,就釋放掉這個互斥鎖,這樣別的線程就有機會訪問該共享資源了。
死鎖
互斥鎖解決了競態(tài)條件的問題,但很不幸同時這也引入了一些其他問題,其中一個就是死鎖。當(dāng)多個線程在相互等待著對方的結(jié)束時,就會發(fā)生死鎖,這時程序可能會被卡住。
看看下面的代碼,它交換兩個變量的值:
voidswap(A, B){? ?
?lock(lockA);?
?? lock(lockB);
inta = A;intb = B;? ? A = b;? ? B = a;? ? unlock(lockB);? ? unlock(lockA);}
大多數(shù)時候,這能夠正常運行。但是當(dāng)兩個線程使用相反的值來同時調(diào)用上面這個方法時:
swap(X,Y);// 線程 1
swap(Y,X);// 線程 2
此時程序可能會由于死鎖而被終止。線程 1 獲得了 X 的一個鎖,線程 2 獲得了 Y 的一個鎖。 接著它們會同時等待另外一把鎖,但是永遠都不會獲得。
再說一次,你在線程之間共享的資源越多,你使用的鎖也就越多,同時程序被死鎖的概率也會變大。這也是為什么我們需要盡量減少線程間資源共享,并確保共享的資源盡量簡單的原因之一