同步(Synchronization)

應用中多線程的存在打開了一個潛在的關於執行多線程安全訪問資源問題。兩個線程修改相同的資源可能會以意想不到的方式相互妨礙。例如,一個線程可能覆蓋另外一個線程的更改或讓應用進入一個未知潛在無效狀態。若是你幸運,毀壞的資源也能致使明顯的性能問題或相對容易追蹤和修復的崩潰。若是你不幸,然而,毀壞的資源可能致使微妙的錯誤,一直不顯現直到好久之後,或者錯誤可能須要對底層編碼設計進行完全檢查。程序員

當涉及到線程安全時,好的設計是最好的保護。避免資源共享和減小線程間的交互使它們不太相互干擾。一個徹底抗干擾的設計並不存在,然而。線程必須交互的狀況下,你須要使用同步工具以確保當它們相互做用是他們這樣作是安全的。web

OSX和iOS提供大量的同步工具,延伸到提供互斥訪問應用中序列事件的工具。如下章節描述這些工具以及如何在你的代碼中使用它們來安全訪問程序中的資源。安全

同步工具

爲了防止不一樣線程意外的更改數據,你能夠設計你的應用沒有同步問題或者你可使用同步工具。儘管避免同步問題是徹底可取的,這並不老是可能。如下章節描述供你使用的同步工具的基本類別。數據結構

原子操做

原子操做是同步的一種簡單形式,用於簡單數據類型。原子操做的優勢是他們不阻塞競爭線程。對於簡單的操做,例如增長計時器變量,比鎖這會有更好的性能。多線程

OSX和iOS包含許多操做來執行32位和64位值的基本數學和邏輯操做。這些操做是比較-交換、測試-設置、測試-清除操做的原子版本。關於支持的原子操做的列表,見 /usr/include/libkern/OSAtomic.h 頭文件或原子(atomic)手冊頁。函數

內存屏障和不穩定變量

爲了實現最優性能,編譯器經常從新排序彙編級別指令來儘量保持處理器指令管道完整。做爲這種優化的一部分,編譯器可能從新排序指令,當它認爲這樣作不會產生不正確的數據,這些指令會訪問主要內存。不幸的是,檢測全部依賴內存的操做對編譯器來講不可能。若是看似獨立的變量相互影響,編譯器優化可能以錯誤的順序更新這些變量,產生不正確的結果。工具

內存屏障是一種非阻塞同步工具用來確保內存操做以正確的順序發生。內存屏障就像一個柵欄,迫使處理器完成任何在柵欄前面的加載和存儲操做,而後才容許執行柵欄後面的加載和存儲操做。內存屏障一般用於確保線程(但看上去是另外一個線程)的內存操做以預期的順序發生。在這種狀況下沒有內存屏障可能讓其餘線程看到貌似不可能的結果。(例如,見維基百科的內存屏障(memorybarriers)條目。)爲了使用內存屏障,你只需在你代碼適當的位置調用OSMemoryBarrier函數。性能

不穩定變量應用另外一種類型的內存來約束獨立變量。編譯器一般經過加載變量值到寄存器來優化代碼。對於局部變量,這一般不是一個問題。然而若是該變量對另外一個線程是可見的,這樣的優化可能會阻止其餘線程注意該值的變化。變量使用volatile 關鍵字,每次使用該變量時,將強制編譯器從內存中加載該變量。若是變量的值可能在任什麼時候候被外部來源改變,且編譯器沒法檢測到,你能夠聲明一個變量爲volatile 。測試

由於內存屏障和不穩定變量減小編譯器可執行的優化,應該謹慎使用它們並只在須要的地方使用以確保正確性。關於使用內存屏障的更多信息,參見OSMemoryBarrier 手冊頁。優化

鎖是最經常使用的同步工具之一。你可使用鎖來保護你代碼的關鍵部分,這段代碼只容許一個線程訪問。例如,一個關鍵部分可能操做特定數據結構或使用一些最多一次支持一個客戶端的資源。經過這章的鎖,你能夠排除其餘線程進行影響代碼正確性的更改。

表4-1 列出了程序員經常使用的一些鎖。OS X和iOS提供大部分類型鎖的實現,但不是所有。對於不支持鎖類型,說明列解釋了這些鎖在平臺上不直接實現的緣由。

相關文章
相關標籤/搜索