Just My Life & My Work

[iOS] atomic和nonatomic

已經開發iOS App超過五年的我,在宣告Property Attributes一直以來都是用nonatomic,尚未使用到預設的atomic

@property (strong, nonatomic) UIWindow *window;

現在有個情況是有好幾個Thread有機會同時存取(setget)同一個Property,此時就有必要使用atomic。可是了解後發現,atomic不能保證我存取的值是正確的,到底是怎麼一回事呢?

Atomic vs. Non-Atomic Operations.png

首先來看知名的Realm怎麼解釋兩者nonatomicatomic

atomic (default)

Atomic is the default: if you dont type anything, your property is atomic. An atomic property is guaranteed that if you try to read from it, you will get back a valid value. It does not make any guarantees about what that value might be, but you will get back good data, not just junk memory. What this allows you to do is if you have multiple threads or multiple processes pointing at a single variable, one thread can read and another thread can write. If they hit at the same time, the reader thread is guaranteed to get one of the two values: either before the change or after the change. What atomic does not give you is any sort of guarantee about which of those values you might get. Atomic is really commonly confused with being thread-safe, and that is not correct. You need to guarantee your thread safety other ways. However, atomic will guarantee that if you try to read, you get back some kind of value.

nonatomic

On the flip side, non-atomic, as you can probably guess, just means, dont do that atomic stuff. What you lose is that guarantee that you always get back something. If you try to read in the middle of a write, you could get back garbage data. But, on the other hand, you go a little bit faster. Because atomic properties have to do some magic to guarantee that you will get back a value, they are a bit slower. If it is a property that you are accessing a lot, you may want to drop down to nonatomic to make sure that you are not incurring that speed penalty.

看了對岸朋友的解釋,我直接飲用過來~

其中Atomic is really commonly confused with being thread-safe, and that is not correct. You need to guarantee your thread safety other ways.這句話明確說明Atomic不能保證對像多線程的安全。所以Atomic 不能保證對像多線程的安全。它只是能保證你訪問的時候給你返回一個完好無損的Value而已。舉個例子:

如果線程A呼叫getter,與此同時線程B 、線程C呼叫setter——那最後線程A get到的值,有3種可能

  1. 可能是BC set 之前原始的值,
  2. 也可能是B set 的值,
  3. 也可能是C set 的值。

同時,最終這個屬性的值,可能是B set 的值,也有可能是C set 的值。所以atomic可並不能保證對象的線程安全。

atomicnonatomic的比較:

1atomicnonatomic用來決定編譯器生成的gettersetter是否為原子操作。

2atomic:系統生成的getter/setter 會保證getset 操作的完整性,不受其他線程影響。getter 還是能得到一個完好無損的對象(可以保證數據的完整性),但這個對像在多線程的情況下是不能確定的,比如上面的例子。

也就是說:如果有多個線程同時調用setter的話,不會出現某一個線程執行完setter全部語句之前,另一個線程開始執行setter情況,相當於函數頭尾加了鎖一樣,每次只能有一個線程調用對象的setter方法,所以可以保證數據的完整性。

atomic所說的線程安全只是保證了gettersetter存取方法的線程安全,並不能保證整個對像是線程安全的。

3nonatomic:就沒有這個保證了,nonatomic返回你的對象可能就不是完整的value。因此,在多線程的環境下原子操作是非常必要的,否則有可能會引起錯誤的結果。但僅僅使用atomic並不會使得對象線程安全,我們還要為對象線程添加lock來確保線程的安全。

4nonatomic的速度要比atomic的快。

5atomicnonatomic的本質區別其實也就是在setter方法上的操作不同

我們來看一下兩者settergetter方法如何實現:

nonatomic對象settergetter方法的實現:

- (void)setCurrentImage:(UIImage *)currentImage
{
    if (_currentImage != currentImage) {
        [_currentImage release];
        _currentImage = [currentImage retain];
    }
}

- (UIImage *)currentImage
{
    return _currentImage;
}

atomic對象settergetter方法的實現:

- (void)setCurrentImage:(UIImage *)currentImage
{
    @synchronized(self) {
        if (_currentImage != currentImage) {
            [_currentImage release];
            _currentImage = [currentImage retain];
        }
    }
}

- (UIImage *)currentImage
{
    @synchronized(self) {
        return _currentImage;
    }
}

之後要研究怎麼使用Lock來保證存取得值正確囉~

參考:Property Attributes in Objective-CiOS atomic nonatomic 的區別atomic nonatomic 有什麼區別?Atomic vs. Non-Atomic OperationsOC @property 知多少

廣告

隨意留個言吧:)~

在下方填入你的資料或按右方圖示以社群網站登入:

WordPress.com 標誌

您的留言將使用 WordPress.com 帳號。 登出 /  變更 )

Twitter picture

您的留言將使用 Twitter 帳號。 登出 /  變更 )

Facebook照片

您的留言將使用 Facebook 帳號。 登出 /  變更 )

連結到 %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

標籤雲

%d 位部落客按了讚: