2012-08-23 20 views
3

在我的Cocoa/iOS的應用程序,我有一個靜態double變量(姑且稱之爲foo),它必須是:可可:最輕量級的方式來同步訪問一個雙?

  1. 通過我的應用程序的一部分在後臺線程更新
  2. 由另一部分看我的在主線程上的應用程序

我正在尋找最輕量級的方式來同步訪問foo

:我知道,在這些情況下,最簡單的解決方案通常是調整代碼,使得只有一個線程訪問變量,因此沒有同步是必要的。假設我已經確定在這種情況下限制foo訪問單個線程是不可能的(可能在步驟中採取的動作發生得如此之快/通常不希望線程切換)。請不要回答「限制foo訪問一個線程」的答案。我正在尋找替代品。


我現在的理解是,使用volatile變量是同步訪問foo最輕量級的方式。所以foo聲明是這樣的:

static volatile double foo = 60.0; 

後臺線程編寫代碼是一樣的東西:

foo = 90.0; 

主線程讀取的代碼是一樣的東西:

double bar = 0.0; 
bar = foo; 
// use bar here … 


一些問題:

  1. 主線程保證在後臺線程上寫入更新後的foo值(假設foo被聲明爲volatile)? IOW,我做了足夠的工作以確保兩個線程能夠看到對方的讀/寫操作的結果嗎?
  2. 我假設在這種情況下,使用volatile作爲double的值更快/更輕量級/更可取,而不是像@synchronized塊或NSLock那樣的互斥鎖。真的嗎? IOW,是volatile這個特殊情況的最佳解決方案?
+2

易失性不保證原子性。 – mkb

+1

@mkb ...尤其是當標記爲易失性的想法大於機器字時,這可能就是這種情況。 –

+0

@mkb真棒。好信息。如果那是真的,那麼我認爲在這種情況下volatile不會起作用。 –

回答

3

1)volatile不是這裏原子基元的替代品。關閉,但不完全。

2)問題volatile是,它不是正確,正如你現在知道的。

理想情況:您可以訪問最新的原子語言功能,例如C++中的_Atomic和C++ 11中的<atomic>

如果沒有,那麼你既可以使用一個64位的整數和原子功能,您可以通過值讀取,然後轉移到一個double,或者你可以使用一個簡單的pthread_mutex_t甚至可能是一個自旋鎖(非常小心自旋鎖)。

但是......如果您只是將更改發佈到主線程運行循環的值(如果這是一個選項),那可能會更好。

+0

thx @Justin。我開始認爲,在這種特殊情況下,我不會選擇獨佔線程訪問,這對我會更好。 –

+0

@ToddDitchendorf是的,它真的取決於你在做什麼 - 有一些角落的情況下消息的主線程的變化不是一個選項(實時/ nolock)。不通知的問題在於,您經常最終輪換或輪詢更改。所以,我可能只是將其縮小到內建原子,或者OSAtomic read->使用OSAtomic.h函數移動,如果這不是一個選項。 – justin

1

GCC有atomic primitives這可能是你需要的。我不知道在構建iOS時這些支持情況如何,並且可能會根據您使用的是gcc,llvm-gcc還是clang而有所不同。

2

我會用GCD來創建一個併發調度隊列來管理對變量的訪問。讀者可以簡單地

__block double bar; 
dispatch_async(foo_queue, ^{ bar = foo; }); 

和寫入可以用一個調度屏障:

dispatch_barrier_async(foo_queue, ^{ foo = someOtherFoo; }); 

dispatch_barrier_async呼叫確保任何未決的讀取器塊被完全執行,則寫入塊將被執行並且該值在更多閱讀器塊可以執行之前更新。

這是蘋果在WWDC的一些GCD視頻中推薦的模式。

+0

這太棒了。我還沒有看到。很高興瞭解它。謝謝。 –

3

可可有內置的基元。查看OSAtomic.h的內容

您可以使用OSAtomicCompareAndSwap64Barrier以原子方式編寫(正確對齊和易失性)雙精度值。您在閱讀之前可能還需要OSMemoryBarrier以確保您看到最新的價值。我相信這隻適用於64位體系結構,因爲32位體系結構可能不會以原子方式讀取64位double。

相關問題