web-dev-qa-db-ja.com

Objective-Cのアトミックプロパティとスレッドセーフ

私が読んだほとんどの議論では、プロパティをアトミックにすることはスレッドセーフであることを保証するものではなく、1つのオブジェクトが別のオブジェクトに書き込んだ結果として返される値がゴミにならないことを保証することを示しています同時に読み込もうとしています。

3番目のオブジェクトが書き込みを行う可能性があるため、これはスレッドセーフではないこと、およびアクセスするオブジェクトがガベージバックを取得しないことは理解していますが、複数のオブジェクトが同時に書き込みを行うため、どの値が返されるかは完全にはわかりません時間、およびそれらの値のいずれかを取得することがあります。

したがって、ガベージを返さないと言うとき、ガベージは、オブジェクトが非アトミックであり、別のオブジェクトが書き込み中にオブジェクトにアクセスしようとした場合、書き込み中に結果が返される可能性があるという意味です書き込みによってもたらされる変更の部分的で不完全なバージョンのみを取得しますか?これは、この意味で「ごみ」とは何ですか?また、どの原子特性が防止に役立ちますか?

27
Doug Smith

Objective Cのatomicプロパティは、部分的な書き込みが表示されないことを保証します。 @propertyには属性atomicがあり、値を部分的にしか書き込むことができません。セッターは次のようなものです。

- (void)setProp:(NSString *)newValue {
    [_prop lock];
    _prop = newValue;
    [_prop unlock];
}

したがって、2つのスレッドが値@ "test"と@ "otherTest"を同時に書き込みたい場合、任意の時点でプロパティはプロパティの初期値または@ "test"または@ "otherTest"のみになります。 nonatomicは高速ですが、値はガベージ値であり、@ "test"/@ "otherTest"(thx @Gavin)またはその他のガベージ値の部分文字列はありません。

しかし、atomicは、単純な使用でのみスレッドセーフです。保証されていません。 Appledoc は次のように言います:

1つのスレッドからのアトミックアクセサーを使用して、人の姓と名の両方が変更されるXYZPersonオブジェクトを考えます。別のスレッドが両方の名前に同時にアクセスすると、アトミックゲッターメソッドは完全な文字列を(クラッシュすることなく)返しますが、それらの値が相互に正しい名前であるという保証はありません。変更前に名にアクセスし、変更後に姓にアクセスすると、一貫性のない、不一致の名前のペアになります。

アトミックの使用にまったく問題はありませんでした。アトミックプロパティに問題がないように、コードをそのように設計しました。

38
Binarian

3番目の段落への回答。基本的にははい。スレッドが数値を書き込んでいる間、原子番号を読み取ることはできません。

たとえば、スレッドがアトミック4バイト数の最初の2バイトを書き込み、その数の読み取りが別のスレッドで要求された場合、その読み取りは4バイトすべてが書き込まれるまで待機する必要があります。

逆に、スレッドが非アトミック4バイト数の最初の2バイトを書き込み、その数の読み取りがその時点で別のスレッドで要求された場合、最初の2つの新しいデータバイトを読み取りますが、古いデータを取得します他の2バイトの前の書き込み操作から。

6
Robert Harvey

ロバート・ハーヴェイの答えは正しいが、人々がしばしば見逃していることを考慮するためのサブケースがある。次のコードを検討してください: http://Pastebin.com/S7XyJm6G

アトミックプロパティは、部分的に書き込まれた値を読み取れないようにするだけでなく、ライフタイムを制御しないオブジェクトを取り戻すこともできません(オブジェクトを保持してから自動解放することでこれを行います)。これは、私がリンクした例のようなシングルスレッドコードでは重要ですが、別のスレッドがオブジェクトをあなたの下から解放する可能性があるマルチスレッドコードではさらに重要です。

3
Catfish_Man

並行プログラミングの場合:

アトミックは、あるスレッド(スレッド#1)と他のスレッド(スレッド#2)で書き込み操作のためにアクセスされるプロパティ値が読み取りまたは書き込み操作のためにアトミック値にアクセスしようとした場合、他のスレッド(スレッド#2)はスレッド#1はタスクを完了します。つまり、先着順でプロパティのアクセスをアトミックに同期します。

非アトミックとは、あるスレッド(スレッド#1)と他のスレッド(スレッド#2)で書き込み操作のためにアクセスされるプロパティ値が読み取りまたは書き込み操作のために非アトミック値にアクセスしようとした場合、他のスレッド(スレッド#2)値はすぐに古い値を取得します

0
Shashi3456643

の明示的な実装

@property(アトミック、保持)NSNumber * count

こうなる

- (NSNumber *)count {
    NSNumber *count;
    @synchronized(self) {
        count = [_count retain]; // +1
    }
    return [count autorelease]; // delayed -1
}

- (void)setCount:(NSNumber *)count {
    id oldValue;
    @synchronized(self) {
        oldValue = _count;
        _count = [count retain];
    }
    [oldValue release];
}

アトミックはプロパティのデフォルトの動作です。アトミックプロパティは、値を取得または設定するときにスレッドセーフのレベルを追加します。つまり、他のスレッドが何をしているかに関係なく、プロパティのゲッターとセッターは常に完全に完了します。これらのプロパティは、非アトミックのプロパティよりもアクセスが少し遅くなります。

そして、明示的に実装します

@property(非アトミック、保持)NSNumber * count

このような

- (NSNumber *)count {
    return _count;
}

- (void)setCount:(NSNumber *)count {
    if (count != _count) {
        id oldValue = _count;
        _count = [count retain];
        [_oldValue release];
    }
}

非アトミックプロパティはスレッドセーフではなく、プロパティを直接返します。これはアトミックプロパティよりも高速になりますが、予防策が講じられない場合、明らかにある程度のリスクが伴います。

これらの非原子特性のセッターとゲッター

0
Suraj K Thomas