web-dev-qa-db-ja.com

スレッドセーフのアトミックと非アトムのどちらですか?

私が検索した結果、不変はスレッドセーフですが、可変はそうではありません。これで結構です。しかし、スレッドセーフについての不可解なメモ、ブログ、アトミック対非アトミックについての回答を得たので、回答について親切に説明してください。

「name」というアトミック文字列プロパティがあり、スレッドAから[self setName:@"A"]を呼び出し、スレッドBから[self setName:@"B"]を呼び出し、スレッドCから[self name]を呼び出すと、すべての操作が別のスレッドが順次実行されます。つまり、1つのスレッドがセッターまたはゲッターを実行している場合、他のスレッドは待機します。これにより、プロパティ "name"の読み取り/書き込みが安全になりますが、別のスレッドDが[name release]を同時に呼び出すと、この操作に関係するsetter/getter呼び出しがないため、この操作がクラッシュする可能性があります。つまり、オブジェクトは読み取り/書き込みセーフ(ATOMIC)ですが、別のスレッドがオブジェクトに任意のタイプのメッセージを同時に送信できるため、スレッドセーフではありません。

プロパティ「name」が非アトミックである場合、上記の例のすべてのスレッド-A、B、C、およびDが同時に実行され、予測できない結果が生成されます。アトミックの場合、A、B、Cのいずれかが最初に実行されますが、Dは引き続き並行して実行できます。

これに関するあなたのコメントは私たちを助けます...

そして私の質問は、"ココアでスレッドセーフか、アトミックか非アトミックか?"です。

29
Anoop Vaidya

ObjCプロパティの場合-どちらもスレッドセーフではありません

アトミックは、スレッドエラーに対して耐性です。全体として、これは興味深いデフォルトです。アトミックを好むシナリオはごくわずかです。 Atomicは正確性の確率を高めることができますが、レベルが低すぎるため、適切なロックメカニズムの代替と見なされます。したがって、スレッドセーフが必要な場合でも、アトミックな読み取り/書き込みの他に同期プリミティブが必要です。スレッドセーフが必要ない場合(たとえば、インスタンスが不変であるか、メインスレッドからのみ実行されるように意図されている場合)、atomicは何も追加しません。

スレッドエラーに対して耐性があることは「品質」ではありません。実際のスレッドエラーを隠蔽し、再現と検出をより困難にするのに役立ちます。

また、ミュータブル型とイミュータブル型は、実際にはスレッドセーフを保証しないことに注意してください。 'Mutable'は、インターフェイスのみを参照するためにObjC名で使用できます。不変のインスタンスの内部には、実際には内部の可変状態がある場合があります。つまり、変更可能なサブクラスを持つ型がスレッドセーフであるとは想定できません。


拡大された質問:

「name」というアトミック文字列プロパティがあり、スレッドAから[self setName:@ "A"]を呼び出す場合、スレッドBから[self setName:@ "B"]を呼び出し、[self name]を呼び出します。スレッドCの場合、異なるスレッドでのすべての操作は順次実行されます。つまり、1つのスレッドがセッターまたはゲッターを実行している場合、他のスレッドは待機します。

すべてのスレッドが同時にプロパティを読み書きしようとした場合、一度にアクセスできるスレッドは1つだけで、プロパティがアトミックな場合、他のスレッドはブロックされます。プロパティが非アトミックである場合、それらはすべて、変数への保護されていない読み取りおよび書き込みアクセスを同時に「持つ」ことになります。

別のスレッドDが[name release]を同時に呼び出すと、この操作に関係するsetter/getter呼び出しがないため、この操作がクラッシュする可能性があります。

正しい。

つまり、オブジェクトは読み取り/書き込みセーフ(ATOMIC)ですが、別のスレッドがオブジェクトに任意のタイプのメッセージを同時に送信できるため、スレッドセーフではありません。

まあ、それは本当にもっとたくさんあります。一般的な例は次のとおりです。

    @interface MONPerson : NSObject

    @property (copy) NSString * firstName;
    @property (copy) NSString * lastName;

    - (NSString *)fullName;

    @end

アトミックまたは非アトミックでは、1つのスレッドがそのインスタンスから読み取り、別のスレッドがそのインスタンスに書き込みを行っている場合は、同期メカニズム(ロックなど)が必要になります。あるMONPersonのfirstNameと別のMONPersonのlastNameになる可能性があります-ゲッターの戻り値が返される前にオブジェクトが変更されている可能性があります。

スレッドA:

p.firstName = @"Rob";

スレッドB:

p.firstName = @"Robert";

スレッドA:

label.string = p.firstName; // << uh, oh -- will be Robert

プロパティ「name」が非アトミックである場合、上記の例のすべてのスレッド-A、B、C、およびDが同時に実行され、予期しない結果が生じます。

正しい-初期症状は、参照カウントの不均衡(リーク、過剰放出)である可能性があります。

アトミックの場合、A、B、Cのいずれかが最初に実行されますが、Dは引き続き並行して実行できます。これについて親切にコメントしてください...

正しい。しかし、上記の例を見ると、アトミックだけでロックを置き換えることはめったにありません。代わりに次のようにする必要があります。

スレッドA:

[p lock]; // << wait for it… … … …
// Thread B now cannot access p
p.firstName = @"Rob";
NSString fullName = p.fullName;
[p unlock];
// Thread B can now access p
label.string = fullName;

スレッドB:

[p lock]; // << wait for it… … … …
// Thread A now cannot access p
…
[p unlock];

アトミックアクセサーは、非アトミックアクセスよりも平均で20倍以上遅くなります。また、クラスがスレッドセーフである必要があり、状態が変更可能である場合、並行シナリオで動作するときにロックを使用することになります。適切なロックは、必要なすべての保証を提供します-アトミックアクセサーはそのシナリオでは冗長であり、アトミックを使用するとCPU時間を追加するだけです。通常のロックのもう1つの良い点は、必要な細分性をすべて備えていることです。アトミックに使用されるスピンロックよりも重いことが多いですが、通常は取得が少なくて済むため、通常のロックを正しく使用すれば、非常に高速になります。 。

64
justin

アトミックは、変数へのアトミックアクセスを保証しますが、コードスレッドを安全にしません。どちらも非アトミックではありません。

「アトミック」の場合、合成されたセッター/ゲッターメソッドは、他のスレッドのセッターアクティビティに関係なく、常に値全体がゲッターから返されるか、セッターによって設定されるようにします。したがって、スレッドBがセッターを呼び出している間にスレッドAがゲッターの途中にある場合、実際の実行可能な値がAの呼び出し元に返されます。非アトミックの場合、そのような保証はありません。

10
Asciiom

atomicは、次のスレッドを安全にします。

self.myProperty = value;

または

id value = self.myProperty

次のスレッドを安全にしません

[myPorperty addObject:value];

Atomicは、プロパティの設定または取得をスレッドセーフにしますが、そのプロパティ自体のメソッドの呼び出しをスレッドセーフにしません。

値の設定または取得には複数のCPU命令を使用できるため、設定または取得が途中で中断され、別のスレッドが前のスレッドの値の設定または取得の進行を無効にする可能性があります。

アトミックは、値を設定または取得して、1つの分割不可能な命令で発生したかのように発生し、他のスレッドが途中で足を踏み入れて混乱させることができないようにします。

不変オブジェクトは変更できないためスレッドセーフであり、ある不変オブジェクトのプロパティを別の不変オブジェクトから変更できるので、アトミックにしない限りパーツは安全ではありません。

8
Nathan Day

ARCの前にスレッドセーフに必要であった、言及されていない「アトミック」の別のプロパティがあります(おそらくまだあります)。最初にそれが必要な理由を説明します。ARCなしで、オブジェクトプロパティを読み取ってすぐに保持するとします。ただし、プロパティの読み取りと保持呼び出しの間に別のスレッドが入り、オブジェクトプロパティをnilに設定すると、オブジェクトの割り当てが解除されます。正常に動作しない割り当て解除されたオブジェクトに保持を送信します。また、タイミングが適切な場合にのみ発生するため、非常にまれなバグになります。これを防ぐために、アトミックオブジェクトプロパティは常に自動解放されたオブジェクトを返します。

1
gnasher729

1)どちらもスレッドセーフではありません。 2)Atomicは読み取り/書き込みセーフです。 3)ただし、スレッドセーフにしたい場合は、ミューテックスロック、スピンロックなどのロックメカニズムをスレッドに実装する必要があります。続きを読む... https://developer.Apple.com/library/ios/documentation/Cocoa/Conceptual/Multithreading/ThreadSafety/ThreadSafety.html

0
Sandeep Rajbhar