--ObjC.cn 并發(fā)編程摘要
線程
線程(thread)是組成進程的子單元流酬,操作系統(tǒng)的調度器可以對線程進行單獨的調度掉盅。
多線程可以在單核 CPU 上同時(或者至少看作同時)運行座韵。操作系統(tǒng)將小的時間片分配給每一個線程敲茄,這樣就能夠讓用戶感覺到有多個任務在同時進行倾芝。如果 CPU 是多核的焚虱,那么線程就可以真正的以并發(fā)方式被執(zhí)行,從而減少了完成某項操作所需要的總時間链嘀。
直接使用線程可能會引發(fā)的一個問題是萌狂,如果你的代碼和所基于的框架代碼都創(chuàng)建自己的線程時,那么活動的線程數(shù)量有可能以指數(shù)級增長怀泊。這在大型工程中是一個常見問題茫藏。例如,在 8 核 CPU 中霹琼,你創(chuàng)建了 8 個線程來完全發(fā)揮 CPU 性能务傲。然而在這些線程中你的代碼所調用的框架代碼也做了同樣事情(因為它并不知道你已經(jīng)創(chuàng)建的這些線程),這樣會很快產生成成百上千的線程枣申。代碼的每個部分自身都沒有問題售葡,然而最后卻還是導致了問題。使用線程并不是沒有代價的忠藤,每個線程都會消耗一些內存和內核資源挟伙。
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)建自定義隊列:串行或者并行隊列。自定義隊列非常強大仰禀,在自定義隊列中被調度的所有 block 最終都將被放入到系統(tǒng)的全局隊列中和線程池中照雁。
強烈建議,在絕大多數(shù)情況下使用默認的優(yōu)先級隊列就可以了答恶。如果執(zhí)行的任務需要訪問一些共享的資源饺蚊,那么在不同優(yōu)先級的隊列中調度這些任務很快就會造成不可預期的行為。這樣可能會引起程序的完全掛起悬嗓,因為低優(yōu)先級的任務阻塞了高優(yōu)先級任務污呼,使它不能被執(zhí)行。
互斥鎖
互斥訪問的意思就是同一時刻包竹,只允許一個線程訪問某個特定資源燕酷。為了保證這一點,每個希望訪問共享資源的線程周瞎,首先需要獲得一個共享資源的互斥鎖苗缩,一旦某個線程對資源完成了操作,就釋放掉這個互斥鎖声诸,這樣別的線程就有機會訪問該共享資源了酱讶。
死鎖
互斥鎖解決了競態(tài)條件的問題,但很不幸同時這也引入了一些其他問題彼乌,其中一個就是死鎖泻肯。當多個線程在相互等待著對方的結束時,就會發(fā)生死鎖慰照,這時程序可能會被卡住软免。
看看下面的代碼,它交換兩個變量的值:
voidswap(A, B){? ?
?lock(lockA);?
?? lock(lockB);
inta = A;intb = B;? ? A = b;? ? B = a;? ? unlock(lockB);? ? unlock(lockA);}
大多數(shù)時候焚挠,這能夠正常運行膏萧。但是當兩個線程使用相反的值來同時調用上面這個方法時:
swap(X,Y);// 線程 1
swap(Y,X);// 線程 2
此時程序可能會由于死鎖而被終止。線程 1 獲得了 X 的一個鎖,線程 2 獲得了 Y 的一個鎖榛泛。 接著它們會同時等待另外一把鎖蝌蹂,但是永遠都不會獲得。
再說一次曹锨,你在線程之間共享的資源越多孤个,你使用的鎖也就越多,同時程序被死鎖的概率也會變大沛简。這也是為什么我們需要盡量減少線程間資源共享齐鲤,并確保共享的資源盡量簡單的原因之一