2017-01-12 117 views
3

問題線程安全性 - 目標C

我在哪裏我關注的對象屬性的線程安全的一個項目。我知道當一個屬性是一個對象,如NSString,我可以遇到多線程同時讀寫的情況。在這種情況下,您可能會損壞讀取,並且應用程序可能會崩潰或導致數據損壞。

我的問題是爲原始值類型的性能如BOOL S或NSInteger秒。我想知道如果我可以進入一個類似的情況,當我從多個線程讀取和寫入時讀取一個損壞的值(並且應用程序將崩潰)?無論是哪種情況,我都對爲什麼感興趣。

澄清 - 17年1月13日

我在如果原始值類型屬性是不同易受崩潰最感興趣由於多個線程同時不是一個對象,如的NSMutableString訪問它,自定義創建的對象等。另外,如果在堆棧上訪問內存時相對於多線程而言存在差異。

澄清 - 17年12月1日

謝謝@Rob指着我的答案在這裏:stackoverflow.com/a/34386935/1271826!這個答案有一個很好的例子,表明取決於你所使用的體系結構的類型(32位與64位),當使用基本屬性時,你可以得到一個未定義的結果。

雖然這是對回答我的問題了一大步,我仍然不知道兩件事情:

  • 如果有一個多線程的區別在棧上訪問原始值屬性時VS堆(如我先前提到澄清)?
  • 如果限制一個程序在一個架構上運行,你還能發現自己在訪問的原始值屬性,爲什麼當一個不設防的狀態?

我應該注意到,在這個問題的回答中,圍繞原子vs非原子進行了大量的討論。雖然這通常是一個重要的概念,但這個問題與通過使用原子屬性修飾符或任何其他線程安全方法(如使用GCD)來防止未定義的多線程行爲無關。

+2

使用原子屬性可避免讀取「損壞」值的任何機會。但它不一定避免閱讀「不正確的」值。 – rmaddy

+0

對,我熟悉使用原子vs非原子,但正在讀取可能的原始值類型屬性的「損壞」值?如果是這樣,爲什麼? –

+0

是的,這是可能的。如果您在32位目標上運行https://stackoverflow.com/a/34386935/1271826上的代碼,則會看到損壞的值。 – Rob

回答

2

如果您的原始值類型屬性爲atomic,那麼您可以確信它不會被破壞,因爲您從一個線程讀取它並將其設置爲另一個線程(只要您只使用訪問器方法並且不與直接支持伊娃)。這就是atomic的全部目的。而且,正如您所建議的那樣,這隻適用於基本數據類型(或者既不可變也不具有無狀態的對象)。但在這些狹窄的情況下,atomic可能會有用。

說了這麼多,這是結束該應用程序是線程安全的相去甚遠。它只能保證你訪問這個屬性是線程安全的。但通常線程安全性必須在更廣泛的範圍內考慮。 (我知道你向我們保證這裏不是這種情況,但我認爲這對於未來的讀者來說太快了,以至於atomic足以實現線程安全性,這通常不是。)

例如,如果你的NSInteger屬性是「有多少項目在這個緩存對象」,那麼不僅必須在NSInteger擁有其訪問synchronized,但必須也將結合與緩存的所有交互同步對象(例如,「將項目緩存」和「從緩存中刪除項目」任務)。而且,在這種情況下,因爲你不知何故與這一更廣泛的對象同步的所有交互(例如用GCD隊列,鎖具,@synchronized指令,等等),使得NSInteger財產atomic就成爲多餘的,因此小幅低效率。

底線,在有限的情況下,atomic可提供基本數據類型線程安全的,但經常在更廣的範圍內看時它是不夠的。


你後來說你不關心比賽條件。對於蘋果的價值,蘋果認爲沒有這樣的事情是一場良性競賽。參見WWDC 2016視頻Thread Sanitizer and Static Analysis(約14:40)。

無論如何,你認爲你只是關注值是否可以被損壞或應用程序是否會崩潰:

我想知道如果我能進一個類似的情況,我讀書的時候讀了錯誤值並從多個線程寫入(和應用程序將崩潰)?

底線是,如果您從一個線程讀取而在另一個線程上進行變化,則行爲是簡單的未定義的。它可能有所不同。建議您避免這種情況。

實際上,它是目標架構的一個功能。例如,在32位x86目標上的64位類型(例如long long)上,可以輕鬆檢索損壞的值,其中64位值的一半被設置,而另一半不是。 (例如,請參閱https://stackoverflow.com/a/34386935/1271826。)處理基元類型時,這隻會導致非感性的無效數值。對於指向對象的指針來說,這顯然會產生明顯的影響。

但是,即使你在沒有問題表現的環境的時候,它是避開同步實現線程安全的一個非常脆弱的方法。在新的,意料之外的硬件體系結構上運行或在不同的配置下編譯時,它可能很容易中斷。我建議您觀看Thread Sanitizer and Static Analysis視頻以瞭解更多信息。

+0

謝謝你的回覆。在你的第一段中,你是否說過像NSMutableStrings這樣的可變對象不能被多線程破壞?如果是這樣,他們肯定可以。我問的問題是以多線程損壞的原始值類型爲中心。另外,你能解釋爲什麼原語可以或不能被多線程破壞。我意識到'atomic'的目的是爲了防止腐敗,但是原始數據可能會像對象一樣容易受到多線程的影響? –

+0

首先,我的資格重新評估對象表示「不可變且無狀態」,而不是「可變的」(從技術上講,即使這並不完全正確,但你明白了)。其次,'原子'原始屬性不能被破壞,因爲合成的訪問器方法將同步所有訪問(例如,如果您正在閱讀一個線程,則在另一個線程上寫入將等待直到讀取完成,反之亦然)。 – Rob

+0

最後,我不能調和你的最後一個問題,「是否像對象一樣易受多線程影響的原語?」保證你明白「原子」的作用。 'atomic'將所有訪問器方法同步到屬性中,因此根據定義,這意味着只要您只使用屬性的訪問器方法,就不能通過多個線程破壞基元屬性。有了對象,'atomic'只能確保指向對象的指針的完整性,但顯然不是對象本身,這就是爲什麼可變對象通常是多線程代碼中的問題。 – Rob