原子属性と非原子属性の違いは何ですか?


回答:


1761

最後の2つは同じです。「アトミック」はデフォルトの動作です(実際にはキーワードではないことに注意してください。これはnonatomic - atomicないことによってのみ指定されます -llvm / clangの最近のバージョンでキーワードとして追加されました)。

メソッドの実装を@synthesizingしていると仮定すると、アトミック対非アトミックは生成されたコードを変更します。独自のセッター/ゲッターを作成している場合、atomic / nonatomic / retain / assign / copyは単なる助言です。(注:LLVMの最近のバージョンでは、@ synthesizeがデフォルトの動作になりました。インスタンス変数を宣言する必要もありません。インスタンス変数も自動的に合成_され、誤って直接アクセスしないように名前の先頭に追加されます)。

「アトミック」の場合、合成されたセッター/ゲッターは、他のスレッドでのセッターアクティビティに関係なく、常に値全体がゲッターから返されるか、セッターによって設定されるようにします。つまり、スレッドBがセッターを呼び出している間にスレッドAがゲッターの途中にある場合、実際の実行可能な値(自動解放されたオブジェクト)がAの呼び出し元に返されます。

ではnonatomic、そのような保証は行われません。したがって、nonatomic「アトミック」よりもかなり高速です。

「アトミック」が行わないことは、スレッドの安全性を保証することです。スレッドAがスレッドBとCが異なる値でセッターを呼び出すと同時にゲッターを呼び出している場合、スレッドAは、3つの値のいずれか1つを返します。同様に、オブジェクトは、BまたはCからの値で終了する可能性があり、伝える方法がありません。

マルチスレッドプログラミングの主な課題の1つであるデータの整合性を保証することは、他の方法でも実現できます。

これに追加:

atomicity 複数の依存プロパティが関係している場合、単一のプロパティのスレッド安全性も保証できません。

検討してください:

 @property(atomic, copy) NSString *firstName;
 @property(atomic, copy) NSString *lastName;
 @property(readonly, atomic, copy) NSString *fullName;

この場合、スレッドAはを呼び出してsetFirstName:からを呼び出すことにより、オブジェクトの名前を変更している可能性がありますsetLastName:。その間、スレッドBはfullNameスレッドAの2つの呼び出しの間に呼び出しを行い、新しい姓と古い姓を受け取ります。

これに対処するには、トランザクションモデルが必要です。つまりfullName、依存するプロパティが更新されている間、アクセスを除外できる他の種類の同期や除外です。


21
スレッドセーフなコードが独自のロックなどを行う場合、アトミックプロパティアクセサーをいつ使用しますか?良い例を考えるのに苦労しています。
Daniel Dickison、

8
@bbum理にかなっています。スレッドの安全性はモデルレベルの問題であるという別の回答に対するコメントを気に入っています。IBMスレッドセーフティの定義から:ibm.co/yTEbjY「クラスが正しく実装されている場合、これはクラスがその仕様に準拠していると言う別の方法です。操作のシーケンス(パブリックフィールドの読み取りまたは書き込みとパブリックメソッドの呼び出し)はありません。そのクラスのオブジェクトでは、オブジェクトを無効な状態にしたり、オブジェクトが無効な状態であったりするのを観察したり、クラスの不変条件、前提条件、事後条件に違反したりできる必要があります。」
Ben Flynn

6
@StevenKramerに似た例を次に@property NSArray* astronomicalEvents;示します。UI に表示するデータをリストするがあります。アプリケーションが起動すると、ポインターが空の配列を指し、アプリはWebからデータをプルします。(別のスレッドで)Webリクエストが完了すると、アプリは新しい配列を作成し、プロパティを新しいポインター値にアトミックに設定します。それはスレッドセーフであり、何かが欠落していない限り、ロックコードを記述する必要はありませんでした。私にはかなり便利なようです。
Bugloaf 2013

10
@HotLicks別の楽しいもの。特定のアーキテクチャーでは(どちらを覚えているかわからない)、引数として渡される64ビット値は、レジスターの半分とスタックの半分を渡される場合があります。 atomicクロススレッドの半値読み取りを防ぎます。(それは追跡するのに楽しいバグでした。)
bbum

8
@congliuスレッドAは、retain/autoreleaseダンスなしのオブジェクトを返します。スレッドBがオブジェクトを解放します。スレッドAがブームになります。 atomicスレッドAが戻り値の強い参照(+1保持カウント)を持つようにします。
bbum

360

これはAppleのドキュメントで説明されていますが、実際に何が起こっているかの例を以下に示します。

「アトミック」キーワードがないことに注意してください。「非アトミック」を指定しない場合、プロパティはアトミックですが、「アトミック」を明示的に指定するとエラーが発生します。

「非アトミック」を指定しない場合、プロパティはアトミックですが、必要に応じて、最近のバージョンで「アトミック」を明示的に指定することもできます。

//@property(nonatomic, retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    return userName;
}

- (void) setUserName:(UITextField *)userName_ {
    [userName_ retain];
    [userName release];
    userName = userName_;
}

ここで、アトミックバリアントはもう少し複雑です。

//@property(retain) UITextField *userName;
//Generates roughly

- (UITextField *) userName {
    UITextField *retval = nil;
    @synchronized(self) {
        retval = [[userName retain] autorelease];
    }
    return retval;
}

- (void) setUserName:(UITextField *)userName_ {
    @synchronized(self) {
      [userName_ retain];
      [userName release];
      userName = userName_;
    }
}

基本的に、アトミックバージョンはスレッドの安全性を保証するためにロックを取得する必要があります。また、オブジェクトの参照カウント(およびそれをバランスさせるための自動解放カウント)をバンプして、呼び出し側にオブジェクトが存在することを保証します。別のスレッドが値を設定していて、参照カウントが0に低下した場合、潜在的な競合状態になります。

プロパティがスカラー値であるかオブジェクトであるか、および保持、コピー、読み取り専用、非アトミックなどがどのように相互作用するかに応じて、これらがどのように機能するかについて、実際には多数の異なるバリアントがあります。一般に、プロパティシンセサイザは、すべての組み合わせに対して「正しいこと」を行う方法を知っています。


8
@Louis Gerbarg:同じオブジェクト(userName == userName_)を割り当てようとすると、(nonatomic、retain)セッターのバージョンが正しく機能しないと思います
Florin

5
コードは少し誤解を招く可能性があります。どのアトミックゲッター/セッターが同期されるかについて保証はありません。重要なことに、@property (assign) id delegate;は何にも同期されません(iOS SDK GCC 4.2 ARM -Os)。これは、との間に競合があることを意味[self.delegate delegateMethod:self];foo.delegate = nil; self.foo = nil; [super dealloc];ます。参照してくださいstackoverflow.com/questions/917884/...
TCを。

@fyolnish私は_val/ valが何であるかわかりませんが、いいえ、本当にではありません。アトミックcopy/ retainプロパティのゲッターは、セッターが別のスレッドで呼び出されたためにrefcountがゼロになるオブジェクトを返さないことを確認する必要があります。上書きして解放し、自動解放して保持のバランスを取ります。これは基本的に、ゲッターとセッターの両方がロックを使用する必要があることを意味します(メモリレイアウトが修正された場合、CAS2命令で実行できるはずです。悲しいことに-retain、メソッド呼び出しです)。
tc。

@tcそれはかなり長い間ですが、私が書くつもりだったのはおそらくこれでしたgist.github.com/fjolnir/5d96b3272c6255f6baaeしかし、はい、古い値がsetFooの前にリーダーによって読み取られる可能性があります:戻り、読者はそれを返します。しかし、セッターが-releaseではなく-autoreleaseを使用した場合、それはそれを修正するでしょう。
Fjölnir

@fyolnish残念ながら、いいえ:ゲッターのスレッドで自動解放される必要がある一方で、セッターのスレッドで自動解放されます。また、再帰を使用しているため、スタックが不足する可能性があります(スリム)。
tc。

170

原子

  • デフォルトの動作です
  • 別のプロセスが変数にアクセスする前に、CPUによって現在のプロセスが完了していることを確認します
  • プロセスが完全に完了することが保証されるため、高速ではありません

非アトミック

  • デフォルトの動作ではありません
  • より高速(合成コードの場合、つまり@propertyと@synthesizeを使用して作成された変数の場合)
  • スレッドセーフではない
  • 2つの異なるプロセスが同じ変数に同時にアクセスすると、予期しない動作が発生する可能性があります

137

違いを理解する最良の方法は、次の例を使用することです。

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

これにより、プロパティ "name"の読み取り/書き込みは安全になりますが、別のスレッドDが[name release]同時に呼び出されると、この操作に関係するsetter / getter呼び出しがないため、この操作がクラッシュする可能性があります。つまり、オブジェクトは読み取り/書き込みセーフ(ATOMIC)ですが、別のスレッドがオブジェクトに任意のタイプのメッセージを同時に送信できるため、スレッドセーフではありません。開発者は、そのようなオブジェクトのスレッドセーフを確保する必要があります。

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


116

構文とセマンティクスは、この質問に対する他の優れた回答によってすでに明確に定義されています。実行パフォーマンスは詳細に記述されていないため、回答を追加します。

これら3つの機能的な違いは何ですか?

私はいつもデフォルトをかなり好奇心が強いと考えていました。私たちが取り組んでいる抽象化レベルでは、クラスのアトミックプロパティをビヒクルとして使用して100%スレッドセーフティを達成することは、例外的なケースです。真に正しいマルチスレッドプログラムの場合、プログラマによる介入はほぼ確実に必要です。一方、パフォーマンス特性と実行については、まだ詳しく説明されていません。何年にもわたってマルチスレッド化されたプログラムをいくつか書いてきnonatomicたので、アトミックはどんな目的にも向いていないので、自分のプロパティをずっと宣言していました。この質問の原子的および非原子的特性の詳細の議論中に、私はいくつかのプロファイリングを行っていくつかの奇妙な結果に遭遇しました。

実行

OK。最初に明らかにしたいのは、ロックの実装が実装定義であり、抽象化されていることです。ルイは@synchronized(self)彼の例で使用します-私はこれを一般的な混乱の原因として見ました。実装は実際には使用しません@synchronized(self)。オブジェクトレベルのスピンロックを使用します。ルイのイラストは、私たちがよく知っている構成を使用した高レベルのイラストに適していますが、使用しないことを知っておくことが重要です@synchronized(self)です。

もう1つの違いは、アトミックプロパティはゲッター内でオブジェクトを保持/解放するということです。

パフォーマンス

これが興味深い部分です。競合ない(たとえば、シングルスレッド)ケースでアトミックプロパティアクセスを使用したパフォーマンスは、場合によっては非常に高速になることがあります。理想的ではない場合では、アトミックアクセスを使用すると、のオーバーヘッドの20倍以上のコストがかかる可能性がありnonatomicます。7スレッドを使用したコンテストのケースは、3バイトの構造体(2.2 GHz Core i7クアッドコア、x86_64)の。3バイトの構造体は、非常に遅いプロパティの例です。

興味深い補足:3バイトの構造体のユーザー定義のアクセサーは、合成されたアトミックアクセサーよりも52倍高速でした。または合成された非アトミックアクセサーの84%の速度。

争われたケースのオブジェクトも50回を超える可能性があります。

実装の最適化とバリエーションの数が多いため、これらのコンテキストで実際の影響を測定することは非常に困難です。「プロファイリングして問題がない限り、信頼してください」のようなメッセージをよく耳にします。抽象化レベルのため、実際の影響を測定することは実際には非常に困難です。プロファイルから実際のコストを収集することは、非常に時間がかかる可能性があり、抽象化のため、非常に不正確です。同様に、ARCとMRCは大きな違いをもたらす可能性があります。

そこで、プロパティアクセスの実装に焦点を当てずに一歩objc_msgSend下がって、のような通常の容疑者を含めてNSString競合ないケースでのゲッターへの多くの呼び出しの実際の高レベルの結果(秒単位の値)を調べます。

  • MRC | 非原子| 手動で実装したゲッター:2
  • MRC | 非原子| 合成ゲッター:7
  • MRC | アトミック| 合成ゲッター:47
  • ARC | 非原子| 合成ゲッター:38(注:ARCによる参照カウントの循環の追加)
  • ARC | アトミック| 合成ゲッター:47

おそらくご想像のとおり、参照カウントのアクティビティ/循環は、アトミックおよびARCの下での重要な貢献者です。また、競合するケースでは大きな違いが見られます。

パフォーマンスには細心の注意を払っていますが、それでもセマンティクスを第一に考えています。一方、多くのプロジェクトでは、パフォーマンスの優先度は低くなっています。ただし、使用するテクノロジーの実行の詳細とコストを知っていても、害はありません。ニーズ、目的、および能力に適したテクノロジーを使用する必要があります。うまくいけば、これにより数時間の比較が節約され、プログラムを設計するときに、より適切な情報に基づいた決定を行うのに役立ちます。


MRC | アトミック| 合成ゲッター:47 ARC | アトミック| 合成ゲッター:47何が同じになるのですか?ARCはオーバーヘッドを増やすべきではありませんか?
SDEZero 2012

2
したがって、アトミックプロパティが悪い場合、それらはデフォルトです。ボイラープレートコードを増やすには?
Kunal Balani 2013

@ LearnCocos2D私は同じマシンで10.8.5をテストしましたが、10.8をターゲットにしており、NSString不滅ではない シングルスレッドの競合しないケースを対象としています。- -ARC atomic (BASELINE): 100% -ARC nonatomic, synthesised: 94% -ARC nonatomic, user defined: 86% -MRC nonatomic, user defined: 5% -MRC nonatomic, synthesised: 19% -MRC atomic: 102%今日の結果は少し異なります。@synchronized比較はしていませんでした。@synchronizedは意味的に異なり、重要な並行プログラムがある場合、私はそれを良いツールとは見なしません。スピードが必要な場合は避けてください@synchronized
2013

このテストはどこかでオンラインで行っていますか?:私はここに鉱山を追加し続けるgithub.com/LearnCocos2D/LearnCocos2D/tree/master/...
LearnCocos2D

@ LearnCocos2D申し訳ありませんが、人間が使用できるように準備していません。
ジャスティン2013

95

原子 =スレッドセーフ

非アトミック =スレッドセーフなし

スレッドセーフティ:

インスタンス変数は、ランタイム環境によるそれらのスレッドの実行のスケジューリングやインターリーブに関係なく、複数のスレッドからアクセスされたときに正しく動作し、呼び出し側のコードで追加の同期やその他の調整が行われていなければ、スレッドセーフです。

私たちの文脈では:

スレッドがインスタンスの値を変更した場合、変更された値はすべてのスレッドで使用でき、一度に1つのスレッドのみが値を変更できます。

使用する場所 atomic

マルチスレッド環境でインスタンス変数にアクセスする場合。

の意味atomic

ないの速さでnonatomicあるためnonatomic、実行時からその上の任意のウォッチドッグ作業を必要としません。

使用する場所 nonatomic

インスタンス変数が複数のスレッドによって変更されない場合は、それを使用できます。パフォーマンスが向上します。


3
ここで言うことはすべて正しいですが、今日のプログラミングでは、最後の文は本質的に「間違った」ものです。この方法で「パフォーマンスを改善」しようとするのは本当に考えられないことです。(つまり、その光年以内に到達する前は、「ARCを使用していない」、「NSStringは遅いので使用していない」などになります。)極端な例を言うと、「チーム、コードが遅くなるので、コードにコメントを入れないでください。」信頼性を損なうために(存在しない)理論上のパフォーマンスの向上を望む現実的な開発パイプラインはありません。
Fattie

3
@JoeBlowあなたはここでそれを確認することができ、その事実developer.apple.com/library/mac/documentation/Cocoa/Conceptual/...を
Durai Amuthan.H

1
FWIWのDuraiは、そのリンクが「原子=スレッドセーフティ」の論文と直接矛盾しています。ドキュメントでAppleは「プロパティの原子性はオブジェクトのスレッドセーフと同義ではない」と明言しています。実際には、スレッドの安全性を達成するには、atomicで十分であることはほとんどありません。
Rob

69

私はここに原子と非原子の特性のかなりよく説明された説明を見つけました。以下は、同じものからの関連テキストです。

「アトミック」とは、分解できないことを意味します。OS /プログラミング用語では、アトミック関数呼び出しは中断できないものです-関数全体を実行する必要があり、完了するまで、OSの通常のコンテキスト切り替えによってCPUからスワップアウトされません。あなたが知らなかった場合に備えて:CPUは一度に1つのことしかできないため、OSはCPUへのアクセスを回転させて、すべての実行中のプロセスを小さなタイムスライスで実行し、錯覚を与えますマルチタスクの。CPUスケジューラは、実行中の任意の時点で(たとえ関数呼び出しの途中であっても)プロセスを中断することができます(実際に中断します)。したがって、2つのプロセスが同時に変数を更新しようとする可能性がある共有カウンタ変数の更新などのアクションでは、それらを「原子的に」実行する必要があります。つまり、各更新アクションは、他のプロセスをスワップできる前に完全に終了する必要があります。 CPU。

したがって、この場合のアトミックは、属性リーダーのメソッドを中断できないことを意味します。つまり、メソッドによって読み取られる変数は、他のスレッド/呼び出し/関数が取得するため、途中で値を変更できないことを意味しますCPUにスワップ。

atomic変数は中断できないため、任意の時点で変数に含まれる値は(スレッドロック)破損しないことが保証されますが、このスレッドロックを確保すると、変数へのアクセスが遅くなります。non-atomic一方、変数はそのような保証をしませんが、より高速なアクセスの贅沢を提供します。要約するとnon-atomic、変数が複数のスレッドによって同時にアクセスされないことがわかっている場合は、処理を高速化します。


1
リンクが壊れています。;(
Rob

それがリンクの問題です:(幸いにも、私は私の回答に関連テキストを引用しました
tipycalFlow

67

非常に多くの記事を読み、Stack Overflowの投稿を読み、可変プロパティ属性をチェックするデモアプリケーションを作成した後、すべての属性情報をまとめることにしました。

  1. atomic // デフォルト
  2. nonatomic
  3. strong = retain // デフォルト
  4. weak = unsafe_unretained
  5. retain
  6. assign // デフォルト
  7. unsafe_unretained
  8. copy
  9. readonly
  10. readwrite // デフォルト

記事「iOSの変数プロパティの属性または修飾子」では、上記のすべての属性を見つけることができます。これは間違いなく役立ちます。

  1. atomic

    • atomic 1つのスレッドのみが変数にアクセスすることを意味します(静的型)。
    • atomic スレッドセーフです。
    • しかし、パフォーマンスが遅い
    • atomic デフォルトの動作です
    • ガベージコレクションされていない環境(つまり、retain / release / autoreleaseを使用する場合)のアトミックアクセサーは、ロックを使用して、別のスレッドが値の正しい設定/取得に干渉しないようにします。
    • 実際にはキーワードではありません。

    例:

        @property (retain) NSString *name;
    
        @synthesize name;
  2. nonatomic

    • nonatomic 複数のスレッドが変数にアクセスすることを意味します(動的タイプ)。
    • nonatomic スレッドセーフではありません。
    • しかし、それはパフォーマンスが速いです
    • nonatomicデフォルトの動作ではありません。nonatomicproperty属性にキーワードを追加する必要があります。
    • 2つの異なるプロセス(スレッド)が同時に同じ変数にアクセスすると、予期しない動作が発生する可能性があります。

    例:

        @property (nonatomic, retain) NSString *name;
    
        @synthesize name;

どのように割り当て、強い/保持をデフォルトにすることができますか?
BangOperator

strongはARCに付属し、retainはARCより前のデフォルト
でした

56

原子:

Atomicは、プロパティへのアクセスがアトミックな方法で実行されることを保証します。たとえば、常に完全に初期化されたオブジェクトを返します。あるスレッドのプロパティのget / setは、別のスレッドがアクセスする前に完了する必要があります。

次の関数が2つのスレッドで同時に発生することを想像すると、結果がきれいにならない理由がわかります。

-(void) setName:(NSString*)string
{
  if (name)
  {
    [name release]; 
    // what happens if the second thread jumps in now !?
    // name may be deleted, but our 'name' variable is still set!
    name = nil;
  }

  ...
}

長所: 完全に初期化されたオブジェクトを毎回返すので、マルチスレッドの場合に最適です。

短所: パフォーマンスが低下し、実行が少し遅くなります

非原子:

Atomicとは異なり、完全に初期化されたオブジェクトが毎回戻ることは保証されません。

長所: 非常に高速な実行。

短所: マルチスレッドの場合のガベージバリューの可能性。


5
そのコメントはあまり意味がありません。明確にできますか?Appleサイトの例を見ると、atomicキーワードは、オブジェクトのプロパティを更新するときにオブジェクトで同期します。
Andrew Grant、

52

最初の最も簡単な答え:2番目の2つの例に違いはありません。デフォルトでは、プロパティアクセサーはアトミックです。

ガベージコレクションされていない環境(つまり、retain / release / autoreleaseを使用する場合)のアトミックアクセサーは、ロックを使用して、別のスレッドが値の正しい設定/取得に干渉しないようにします。

マルチスレッドアプリを作成する際の詳細やその他の考慮事項については、AppleのObjective-C 2.0ドキュメントの「パフォーマンスとスレッド」セクションを参照してください。


8
2つの理由。まず、合成コードの方が高速に生成されます(ただし、スレッドセーフコードは生成されません)。第2に、アトミックではないカスタマーアクセサーを作成している場合は、将来のユーザーに対して、実装せずにインターフェースを読み取るときにコードがアトミックでないことを注釈できます。
Louis Gerbarg、2009


31

Atomicは、1つのスレッドのみが変数にアクセスすることを意味します(静的型)。Atomicはスレッドセーフですが、遅いです。

非アトミックとは、複数のスレッドが変数(動的型)にアクセスすることを意味します。非アトミックはスレッドに対して安全ではありませんが、高速です。


14

Atomicはスレッドセーフであり遅く十分に保証されます(保証されません)、同じゾーンでアクセスを試行しているスレッドの数に関係なく、ロックされた値のみが提供さ。アトミックを使用する場合、この関数内に記述されたコードの一部は、一度に1つのスレッドしか実行できないクリティカルセクションの一部になります。

スレッドの安全性を保証するだけです。それを保証するものではありません。つまり、あなたはあなたの車のエキスパートドライバーを雇っていますが、それでも車が事故に遭わないことを保証するものではありません。ただし、確率はわずかです。

原子-分解できないため、結果は予想されます。非アトミック-別のスレッドがメモリゾーンにアクセスすると変更される可能性があるため、予期しない結果になります。

コードトーク:

プロパティのアトミックなゲッターとセッターをスレッドセーフにします。たとえば、あなたが書いた場合:

self.myProperty = value;

スレッドセーフです。

[myArray addObject:@"Abc"] 

スレッドセーフではありません。


最後の段落がどうなるかわかりませんが、それは単純に間違っています。「プライベートコピー」のようなものはありません。
ピーク

13

「原子」というキーワードはありません

@property(atomic, retain) UITextField *userName;

上記のように使用できます

@property(retain) UITextField *userName;

@property(atomic、retain)NSString * myStringを使用すると問題が発生する Stack Overflowの質問参照してください。


10
「このようなキーワードがあります」というキーワードは、デフォルトでは必須ではなく、デフォルト値であっても、キーワードが存在しないという意味ではありません。
Matthijn 2013

4
これは誤りです。キーワードは存在します。この答えは誤解を招くものであり、私はそれを削除することをお勧めします。
sethfri

12

アトミック(デフォルト)

Atomicがデフォルトです。何も入力しない場合、プロパティはAtomicです。アトミックプロパティは、そこから読み取ろうとすると、有効な値が返されることが保証されています。その値が何であるかについては保証されませんが、ジャンクメモリだけでなく、適切なデータが返されます。これにより、1つの変数を指す複数のスレッドまたは複数のプロセスがある場合、1つのスレッドが読み取り、別のスレッドが書き込みを行うことができます。それらが同時にヒットした場合、リーダースレッドは、変更前または変更後の2つの値のいずれかを取得することが保証されます。アトミックがあなたに与えないものは、あなたがそれらの値のどれを得るかについての何らかの種類の保証です。Atomicは一般的にスレッドセーフであると混同されますが、それは正しくありません。他の方法でスレッドセーフを保証する必要があります。

非原子

反対に、おそらく非アトミックなことは、おそらく推測できるように、「そのアトミックなことをしないこと」を意味します。あなたが失うものは、あなたが常に何かを取り戻すという保証です。書き込みの途中で読み込もうとすると、ガベージデータを取り戻す可能性があります。しかし、その一方で、あなたは少し速く行きます。アトミックプロパティは、値が返されることを保証するために何らかの魔法をかける必要があるため、少し遅くなります。頻繁にアクセスしているプロパティである場合は、非アトミックにドロップダウンして、速度のペナルティが発生しないようにすることができます。

詳細はこちら:https : //realm.io/news/tmi-objective-c-property-attributes/


11

デフォルトはありますatomic、あなたがプロパティを使用するとき、それはあなたのパフォーマンスを費用がかかりますが、それはスレッドセーフであるこの手段。Objective-Cが行うのはロックの設定です。そのため、setter / getterが実行されている限り、実際のスレッドだけが変数にアクセスできます。

ivar _internalを持つプロパティのMRCの例:

[_internal lock]; //lock
id result = [[value retain] autorelease];
[_internal unlock];
return result;

したがって、最後の2つは同じです。

@property(atomic, retain) UITextField *userName;

@property(retain) UITextField *userName; // defaults to atomic

一方nonatomic、コードには何も追加されません。したがって、セキュリティメカニズムを自分でコーディングした場合にのみ、スレッドセーフになります。

@property(nonatomic, retain) UITextField *userName;

キーワードを最初のプロパティ属性として記述する必要はまったくありません。

忘れないでください。これは、プロパティ全体がスレッドセーフであることを意味するものではありません。setter / getterのメソッド呼び出しのみです。しかし、セッターを使用し、その後2つの異なるスレッドで同時にゲッターを使用した場合も、壊れる可能性があります。


10

始める前に:新しいライターを実行するには、メモリ内のすべてのオブジェクトをメモリから解放する必要があることを知っておく必要があります。紙に書いているように、単に何かの上に単に書くことはできません。最初にそれを消去(dealloc)する必要あり、次にそれに書き込むことができます。消去が完了(または半分が完了)し、まだ何も書き込まれていない(または半分が書き込まれている)ときに、読み込もうとすると、非常に問題が発生する可能性があります。アトミックおよび非アトミックは、この問題をさまざまな方法で処理するのに役立ちます。

まずこの質問を読んでから、Bbumの回答を読んでください。さらに、私の要約を読んでください。


atomic 常に保証します

  • 2人の異なる人が同時に読み書きしたい場合、あなたの論文は燃えるだけではありません!->アプリケーションが競合状態になってもクラッシュすることはありません。
  • 1人が書き込みをしようとしていて、8文字のうち4文字しか書き込んでいない場合、途中で読み取ることはできません。読み取りは、8文字すべてが書き込まれたときにのみ実行できます->読み取り(取得)は行われません「まだ書き込み中のスレッド」、つまり、8バイトから書き込むバイトがあり、4バイトしか書き込まれていない場合—その瞬間まで、そこから読み取ることはできません。しかし、クラッシュしないと言ったので、自動解放されたオブジェクトの値から読み取ります。
  • もし前にあなたが書いている以前に紙に書かれた後、誰かがあなたが読みたいたことを消去することができ、まだ読んで。どうやって?Mac OSのゴミ箱に似たものから読み取ります(ゴミ箱はまだ100%消去されていないので...リンボにあります)---> ThreadBが書き込みのために割り当て解除されているときにThreadAが読み取られる場合、次のようになります。 ThreadBによって完全に書き込まれた最後の値からの値、または自動解放プールから何かを取得します。

保持カウントは、Objective-Cでメモリを管理する方法です。オブジェクトを作成すると、保持カウントは1になります。オブジェクトに保持メッセージを送信すると、保持カウントは1ずつ増加します。オブジェクトにリリースメッセージを送信すると、保持カウントは1ずつ減少します。オブジェクトに自動解放メッセージを送信します。その保持カウントは、将来のある段階で1ずつ減少します。オブジェクトの保持カウントが0に減ると、割り当てが解除されます。

  • Atomic スレッドの安全性を保証しませんが、スレッドの安全性を実現するために役立ちます。スレッドセーフティは、コードの記述方法/読み取り/書き込み元のスレッドキューに関連しています。クラッシュしないマルチスレッドのみを保証します。

何?!マルチスレッドとスレッドセーフティは異なりますか?

はい。マルチスレッドとは、複数のスレッドが共有データを同時に読み取ることができ、クラッシュしないことを意味しますが、自動解放されていない値から読み取っていないことを保証するものではありません。スレッドセーフでは、読み取った内容が自動的に解放されないことが保証されます。デフォルトですべてをアトミックにしない理由は、パフォーマンスコストがあり、ほとんどの場合、スレッドセーフを実際には必要としないためです。コードのいくつかの部分でそれが必要であり、それらのいくつかの部分では、ロック、ミューテックス、または同期を使用してスレッドセーフな方法でコードを記述する必要があります。


nonatomic

  • Mac OSのゴミ箱のようなものはないので、常に値を取得するかどうか(<-これは潜在的にクラッシュにつながる可能性があります)も、誰かがあなたの書き込みの途中で読み込もうとしたかどうかも気にしません。メモリへの途中書き込みは紙への途中書き込みとは非常に異なります。メモリでは、以前からクレイジーな愚かな価値を与える可能性がありますが、紙では書き込まれた内容の半分しか表示されません)->クラッシュしないことを保証しないため、自動解放メカニズムは使用しません。
  • 完全に書き込まれた値が読み取られることを保証しません!
  • アトミックより速い

全体として、2つの点で異なります。

  • 自動解放プールの有無によるクラッシュの有無。

  • 「まだ完了していない書き込みまたは空の値」の途中で読み取ることを許可するか、または値が完全に書き込まれたときにのみ読み取りを許可および許可しない。


9

プロパティをマルチスレッドコードで使用している場合は、非アトミック属性とアトミック属性の違いを確認できます。非アトミックはアトミックより速く、アトミックは非アトミックではなくスレッドセーフです。

Vijayendra Tripathiはすでにマルチスレッド環境の例を示しています。


9
  • -Atomicは、1つのスレッドのみが変数(静的型)にアクセスすることを意味します。
  • -Atomicはスレッドセーフです。
  • -しかし、パフォーマンスが遅い

宣言する方法:

アトミックはデフォルトなので、

@property (retain) NSString *name;

AND実装ファイル内

self.name = @"sourov";

3つのプロパティに関連するタスクが

 @property (retain) NSString *name;
 @property (retain) NSString *A;
 @property (retain) NSString *B;
 self.name = @"sourov";

すべてのプロパティは(非同期のように)並行して機能します。

スレッドAから「名前」を呼び出すと、

そして

同時に電話すれば

[self setName:@"Datta"]

スレッドBから

* nameプロパティが非アトミックの場合

  • Aに対して値「Datta」を返します
  • Bに対して値「Datta」を返します

そのため、非アトミックはスレッドセーフでないと呼ばれますが、並列実行のため、パフォーマンスは高速です

* nameプロパティがアトミックの場合

  • Aの値「Sourov」を保証します
  • 次に、Bの値「Datta」を返します

これが、アトミックがスレッドセーフ呼ばれる理由であり、それが読み取り/書き込みセーフと呼ばれる理由です。

このようなシチュエーション操作は順次実行されます。 そしてパフォーマンスが遅い

-非アトミックとは、複数のスレッドが変数(動的タイプ)にアクセスすることを意味します。

-非アトミックはスレッドに対して安全ではありません。

-しかし、パフォーマンスは速い

-Nonatomicはデフォルトの動作ではありません。プロパティ属性に非アトミックキーワードを追加する必要があります。

In Swiftの場合、SwiftプロパティがObjCの意味で非アトミックであることを確認します。1つの理由は、プロパティごとの原子性がニーズに十分であるかどうかを考えるためです。

リファレンス:https : //forums.developer.apple.com/thread/25642

詳細については、ウェブサイトhttp://rdcworld-iphone.blogspot.in/2012/12/variable-property-attributes-or.htmlをご覧ください


4
他の多くのmaaaaanyが言ったように、スレッドセーフでatomicはありません!スレッドの問題に対してより耐性がありますが、スレッドセーフではありません。それは単に値全体、つまり「正しい」値(バイナリレベル)を取得することを保証しますが、決してそれがビジネスロジックの現在の「正しい」値であることを保証しません(過去の値とあなたの論理では無効です)。
アレハンドロイヴァン2017

6

原子性(デフォルト)

Atomicがデフォルトです。何も入力しない場合、プロパティはAtomicです。アトミックプロパティは、そこから読み取ろうとすると、有効な値が返されることが保証されています。その値が何であるかについては保証されませんが、ジャンクメモリだけでなく、適切なデータが返されます。これにより、1つの変数を指す複数のスレッドまたは複数のプロセスがある場合、1つのスレッドが読み取り、別のスレッドが書き込みを行うことができます。それらが同時にヒットした場合、リーダースレッドは、変更前または変更後の2つの値のいずれかを取得することが保証されます。アトミックがあなたに与えないものは、あなたがそれらの値のどれを得るかについての何らかの種類の保証です。Atomicは一般的にスレッドセーフであると混同されますが、それは正しくありません。他の方法でスレッドセーフを保証する必要があります。

非原子

反対に、おそらく非アトミックなことは、おそらく推測できるように、「そのアトミックなことをしないでください」という意味です。あなたが失うものは、あなたが常に何かを取り戻すという保証です。書き込みの途中で読み込もうとすると、ガベージデータを取り戻す可能性があります。しかし、その一方で、あなたは少し速く行きます。アトミックプロパティは、値が返されることを保証するために何らかの魔法をかける必要があるため、少し遅くなります。頻繁にアクセスしているプロパティである場合は、非アトミックにドロップダウンして、速度のペナルティが発生しないようにすることができます。アクセス

礼儀https://academy.realm.io/posts/tmi-objective-c-property-attributes/

アトミシティプロパティの属性(アトミックおよび非アトミック)は、対応するSwiftプロパティ宣言には反映されませんが、Objective-C実装のアトミシティ保証は、インポートされたプロパティがSwiftからアクセスされた場合でも保持されます。

したがって、Objective-Cでアトミックプロパティを定義すると、Swiftで使用してもアトミックなままになります。

礼儀 https://medium.com/@YogevSitton/atomic-vs-non-atomic-properties-crash-course-d11c23f4366c


5

アトミックプロパティは、ゲッターとセッターを実行しているスレッドの数に関係なく、完全に初期化された値を保持することを保証します。

非アトミックプロパティは、同じ値が異なるスレッドから同時にアクセスされた場合に何が起こるかを保証せずに、合成されたアクセサが値を直接設定または返すことを指定します。


3

Atomicは、一度に1つのスレッドのみが変数にアクセスできることを意味します(静的型)。Atomicはスレッドセーフですが、遅いです。

非アトミックとは、複数のスレッドが同時に変数にアクセスできることを意味します(動的型)。非アトミックはスレッドに対して安全ではありませんが、高速です。


1

アトミックを使用している場合、それはスレッドが安全で読み取り専用になることを意味します。非アトミックを使用している場合、それは複数のスレッドが変数にアクセスし、スレッドセーフではないことを意味しますが、高速に実行され、読み取りおよび書き込み操作を実行します。これは動的なタイプです。


1

真実は、彼らがアトミックプロパティを実装するためにスピンロックを使用することです。以下のようなコード:

 static inline void reallySetProperty(id self, SEL _cmd, id newValue, 
      ptrdiff_t offset, bool atomic, bool copy, bool mutableCopy) 
    {
        id oldValue;
        id *slot = (id*) ((char*)self + offset);

        if (copy) {
            newValue = [newValue copyWithZone:NULL];
        } else if (mutableCopy) {
            newValue = [newValue mutableCopyWithZone:NULL];
        } else {
            if (*slot == newValue) return;
            newValue = objc_retain(newValue);
        }

        if (!atomic) {
            oldValue = *slot;
            *slot = newValue;
        } else {
            spin_lock_t *slotlock = &PropertyLocks[GOODHASH(slot)];
            _spin_lock(slotlock);
            oldValue = *slot;
            *slot = newValue;        
            _spin_unlock(slotlock);
        }

        objc_release(oldValue);
    }

0

混乱全体を単純化するために、mutexロックを理解しましょう。

ミューテックスロックは、名前のとおり、オブジェクトの可変性をロックします。したがって、オブジェクトがクラスによってアクセスされる場合、他のクラスは同じオブジェクトにアクセスできません。

iOS @sychroniseでは、mutexロックも提供します。FIFOモードで機能し、同じインスタンスを共有する2つのクラスによってフローが影響を受けないようにします。ただし、タスクがメインスレッド上にある場合は、UIを保持してパフォーマンスを低下させる可能性があるため、アトミックプロパティを使用してオブジェクトにアクセスしないでください。


-1

Atomic:NSLOCKを使用してスレッドをロックすることにより、スレッドの安全を確保します。

非アトミック:スレッドロックメカニズムがないため、スレッドの安全性は保証されません。


-1

アトミックプロパティ:- アトミックプロパティで割り当てられた変数は、スレッドアクセスが1つだけであり、スレッドセーフであり、パフォーマンスの観点で優れている場合、デフォルトの動作になります。

非アトミックプロパティ:- アトミックプロパティで割り当てられた変数、つまりマルチスレッドアクセスがあり、スレッドセーフではなく、パフォーマンスの観点から遅くなる場合、デフォルトの動作があり、2つの異なるスレッドが同時に変数にアクセスする場合予期しない結果が生じます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.