同步工具
雖然避免需要同步的場景是上上策富岳,但并不總能如愿赶站,還是有需要對操作進(jìn)行同步的場景
原子操作
原子操作是簡單數(shù)據(jù)類型適用的一種簡單的同步方式算行,它的優(yōu)勢在于不會阻塞競爭線程呈驶。對于簡單的操作比如計(jì)數(shù)器增1來說努释,原子操作比鎖有更大的性能優(yōu)勢碘梢。
Memory barriers 和 易變變量
為實(shí)現(xiàn)最佳CPU利用率,編譯器會對匯編指令進(jìn)行重排以更充分地利用CPU執(zhí)行流水線伐蒂。作為這個編譯優(yōu)化的一部分煞躬,如果編譯器認(rèn)為不會有產(chǎn)生不正確數(shù)據(jù)的危險(xiǎn),它會對訪問主存的指令進(jìn)行重排,然而對于編譯器來說恩沛,它并不總能將所有對內(nèi)存有依賴的操作都在優(yōu)化中進(jìn)行不會產(chǎn)生問題的重排在扰。因?yàn)楦髯兞恐g是互相影響的,編譯器優(yōu)化可能用錯誤的順序更新這些變量雷客,由此產(chǎn)生潛在的不正確的結(jié)果芒珠。
memory barrier是一種不阻塞線程的確保操作按照了正確順序的同步工具。它的運(yùn)行原理類似于柵欄一樣搅裙,它強(qiáng)制處理器完成memory barrier之前的所有加載和存儲操作妓局,再進(jìn)行其之后的加載和存儲操作,它可以確保某線程中的內(nèi)存操作是按期望的順序進(jìn)行的呈宇。使用memory barrier只需要調(diào)用OSMemoryBarrier函數(shù)即可。
而易變 變量又是另一種內(nèi)存使用的限制了局雄,編譯器經(jīng)常通過將變量值加載進(jìn)寄存器以優(yōu)化存取速度甥啄。對于局部變量,這種做法自然沒有問題炬搭,但如果這個變量在其它線程可見蜈漓,則可能導(dǎo)致它們觀察不到這個變量的值的變化,?因?yàn)橛锌赡苤鞔嬷械淖兞恐狄呀?jīng)被別的線程修改了宫盔,導(dǎo)致寄存器中讀取的值與變量的值已經(jīng)不一樣了融虽,這時候從寄存器中讀取到的值已經(jīng)不是變量的值了。將變量定義為volatile可以強(qiáng)制編譯器每次加載變量時都從主存中讀取灼芭。
鎖
鎖是最常用的同步工具有额,它用來保護(hù)關(guān)鍵代碼段,即一次只允許一個線程訪問的代碼段彼绷。
鎖 | 描述 |
---|---|
Mutex | 互斥鎖扮演資源保護(hù)barrier的角色巍佑,它是確保一種一次只授權(quán)一個線程訪問的信號量,其它想獲取它的線程會在上一個線程使用時一直被阻塞直到鎖被釋放 |
Recursive lock | 它是Mutex鎖的變種寄悯,它允許同一個線程獲取多次萤衰,且直到它悉數(shù)釋放了才會喚醒其它線程試圖訪問它的線程。當(dāng)然這個鎖最初是用于遞歸調(diào)用的場景猜旬,但也可以有多個方法脆栋,每個方法單獨(dú)獲取 |
Read-write lock | 也稱為共享獨(dú)占鎖,這種鎖通常用于保護(hù)讀取頻繁而寫入較少的場景洒擦,且性能優(yōu)異椿争。如果寫線程請求鎖,則會阻塞直到所有 讀線程完成讀取秘遏,而寫線程在等待時丘薛,讀線程會一直阻塞直到寫完 |
Distributed lock | 提供處理級的相互互斥訪問,與真正的互斥鎖不同的是邦危,distributed lock不會阻止或者阻塞進(jìn)程洋侨,它只會簡單地報(bào)告鎖是否繁忙舍扰,由進(jìn)程決定怎樣處理 |
spin lock | 自旋鎖會不斷輪詢其鎖條件直到其條件滿足,自旋鎖大量用于期望鎖的等待時間小的多處理器系統(tǒng)上希坚。在這些場景中边苹,通常更有效的是輪詢而不是阻塞線程,因?yàn)樽枞€程通常意味著耗時的上下文切換和線程數(shù)據(jù)結(jié)構(gòu)的更新裁僧。由于它的輪詢特性个束,系統(tǒng)并不提供任何自旋鎖的實(shí)現(xiàn),但可以在特定場景下輕松對其實(shí)現(xiàn)聊疲,可以參考kernel programming guide中在內(nèi)核中實(shí)現(xiàn)自旋鎖的信息 |
double-checked lock | 不推薦使用 |
條件
condition是另一種允許條件成真時線程間相互通知的信號量茬底,通常用于表明資源的可用性以確保操作按特定的順序進(jìn)行。線程測試condition時获洲,它會阻塞直到其它線程顯式更新條件阱表。其與互斥鎖不同的地方在于它允許多個線程同時訪問condition。其實(shí)類似于生產(chǎn)者消費(fèi)者模式贡珊,它的使用方式中的一種是管理掛起消息池最爬。隊(duì)列中有消息時,會用condition變量signal等待線程门岔,如果來了一條消息爱致,則會signal一次,讓等待線程中的一個取事件處理寒随,如果幾乎同一時間來了兩次糠悯,則會signal condition兩次,喚醒兩個線程妻往。
perform selector routines
cocoa應(yīng)用可以用一種便利而同步的方式向線程傳遞消息逢防,NSObjec對象聲明了在線程上執(zhí)行selector的方法,這些方法異步地傳遞消息蒲讯,而系統(tǒng)確保會同步地在目標(biāo)線程上執(zhí)行這些selector忘朝,每個請求都會在目標(biāo)線程的runloop上排上隊(duì),并按收到的順序進(jìn)行執(zhí)行判帮。