プロパティ宣言の意味atomic
とは?nonatomic
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;
これら3つの操作上の違いは何ですか?
プロパティ宣言の意味atomic
とは?nonatomic
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;
これら3つの操作上の違いは何ですか?
最後の 2 つは同一です。「アトミック」はデフォルトの動作です (これは実際にはキーワードではないことに注意してください。これは--nonatomic
atomic
がないことによってのみ指定されます。最近のバージョンの llvm/clang ではキーワードとして追加されました)。
メソッド実装を @synthesizing していると仮定すると、アトミック対非アトミックは生成されたコードを変更します。独自のセッター/ゲッターを作成している場合、アトミック/非アトミック/保持/割り当て/コピーは単なるアドバイスです。(注: @synthesize は最近のバージョンの LLVM のデフォルトの動作になりました。インスタンス変数を宣言する必要もありません。それらも自動的に合成_
され、偶発的な直接アクセスを防ぐために名前の前に が追加されます)。
「アトミック」を使用すると、合成されたセッター/ゲッターは、他のスレッドでのセッターのアクティビティに関係なく、常にゲッターから値全体が返されるか、セッターによって設定されることを保証します。つまり、スレッド B がセッターを呼び出しているときにスレッド A がゲッターの途中にある場合、実際に実行可能な値 (おそらく自動解放されたオブジェクト) が A の呼び出し元に返されます。
ではnonatomic
、そのような保証はありません。したがって、nonatomic
「アトミック」よりもかなり高速です。
「アトミック」がしないことは、スレッドの安全性について保証することです。スレッド A がゲッターを呼び出し、スレッド B とスレッド C が異なる値でセッターを呼び出している場合、スレッド A は返される 3 つの値のいずれかを取得する可能性があります。同様に、オブジェクトは最終的に B または C からの値になる可能性があり、判断する方法はありません。
マルチスレッド プログラミングの主な課題の 1 つであるデータ整合性の確保は、別の方法で達成されます。
これに追加:
atomicity
複数の依存プロパティが使用されている場合、単一のプロパティのスレッド セーフも保証できません。
検討:
@property(atomic, copy) NSString *firstName;
@property(atomic, copy) NSString *lastName;
@property(readonly, atomic, copy) NSString *fullName;
setFirstName:
この場合、スレッド A は、 を呼び出してから呼び出すことで、オブジェクトの名前を変更できますsetLastName:
。その間、スレッド B はfullName
、スレッド A の 2 つの呼び出しの間に呼び出しを行うことができ、古い姓と結合された新しい名を受け取ります。
これに対処するには、トランザクション モデルが必要です。fullName
つまり、依存プロパティの更新中にアクセスを除外できるようにする、他の種類の同期および/または除外です。
これは Apple のドキュメントで説明されていますが、実際に起こっていることの例を以下に示します。
「atomic」キーワードがないことに注意してください。「nonatomic」を指定しない場合、プロパティはアトミックですが、「atomic」を明示的に指定するとエラーになります。
"nonatomic" を指定しない場合、プロパティはアトミックですが、必要に応じて最近のバージョンでは "atomic" を明示的に指定できます。
//@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_;
}
}
基本的に、アトミック バージョンは、スレッドの安全性を保証するためにロックを取得する必要があり、オブジェクトの参照カウント (およびバランスを取るための自動解放カウント) を増やして、オブジェクトが呼び出し元に対して存在することが保証されるようにします。別のスレッドが値を設定している場合、競合状態になる可能性があり、ref カウントが 0 に低下します。
実際には、プロパティがスカラー値であるかオブジェクトであるか、保持、コピー、読み取り専用、非アトミックなどの相互作用の方法に応じて、これらがどのように機能するかについて多数の異なるバリエーションがあります。一般に、プロパティ シンセサイザーは、すべての組み合わせに対して「正しいこと」を行う方法を知っているだけです。
違いを理解する最良の方法は、次の例を使用することです。
「name」というアトミック文字列プロパティがあり、[self setName:@"A"]
スレッド A から呼び出し[self setName:@"B"]
、スレッド B から呼び出し[self name]
、スレッド C から呼び出すと、異なるスレッド上のすべての操作がシリアルに実行されます。つまり、1 つのスレッドがセッターを実行している場合です。またはゲッター、その後、他のスレッドが待機します。
これにより、プロパティ「name」の読み取り/書き込みが安全になりますが、別のスレッド D が[name release]
同時に呼び出した場合、この操作にはセッター/ゲッター呼び出しが含まれていないため、クラッシュが発生する可能性があります。これは、オブジェクトが読み取り/書き込みセーフ (ATOMIC) であることを意味しますが、別のスレッドが任意のタイプのメッセージをオブジェクトに同時に送信できるため、スレッドセーフではありません。開発者は、そのようなオブジェクトのスレッド セーフを確保する必要があります。
プロパティ「name」が非アトミックの場合、上記の例のすべてのスレッド (A、B、C、および D) が同時に実行され、予期しない結果が生じます。アトミックの場合、A、B、または C のいずれかが最初に実行されますが、D は並列で実行できます。
構文とセマンティクスは、この質問に対する他の優れた回答によって既に明確に定義されています。実行とパフォーマンスが詳しくないため、私の回答を追加します。
これら3つの機能の違いは何ですか?
私は常にアトミックをデフォルトとして非常に興味深いと考えていました。私たちが取り組んでいる抽象化レベルでは、クラスのアトミック プロパティを手段として使用して 100% のスレッド セーフを実現することはまれなケースです。真に正しいマルチスレッド プログラムを作成するには、ほぼ確実にプログラマによる介入が必要です。一方、パフォーマンスの特性と実行については、まだ詳細に説明されていません。何年にもわたって高度にマルチスレッド化されたプログラムをいくつか書いてきnonatomic
たので、アトミックはどのような目的にも適していなかったため、ずっと自分のプロパティを宣言していました。アトミックおよび非アトミック プロパティの詳細についてこの質問で議論しているときに、いくつかのプロファイリングを行ったところ、興味深い結果が得られました。
実行
Ok。最初に明確にしたいことは、ロックの実装は実装定義で抽象化されているということです。ルイスは@synchronized(self)
彼の例で使用しています - 私はこれが混乱の一般的な原因であると見てきました. 実装は実際には使用しません@synchronized(self)
。オブジェクト レベルのスピン ロックを使用します。Louis の図は、私たちがよく知っている構造を使用した高レベルの図に適していますが、 を使用していないことを知っておくことが重要@synchronized(self)
です。
もう 1 つの違いは、アトミック プロパティが getter 内でオブジェクトを保持/解放することです。
パフォーマンス
興味深い点は次のとおりです。競合のない (シングル スレッドなどの) ケースでのアトミック プロパティ アクセスを使用したパフォーマンスは、場合によっては非常に高速になることがあります。理想的とは言えないケースでは、アトミック アクセスを使用すると、 のオーバーヘッドの 20 倍以上のコストがかかる可能性がありnonatomic
ます。一方、7 スレッドを使用したContestedケースは、3 バイト構造体 (2.2 GHz Core i7 Quad Core、x86_64) で 44 倍遅くなりました。3 バイトの構造体は、非常に遅いプロパティの例です。
興味深い補足: 3 バイト構造体のユーザー定義アクセサーは、合成されたアトミック アクセサーよりも 52 倍高速でした。または、合成された非原子アクセサーの 84% の速度。
争われた場合のオブジェクトも 50 回を超えることがあります。
実装の最適化とバリエーションの数が多いため、これらのコンテキストで実際の影響を測定することは非常に困難です。「プロファイリングして問題が発生しない限り、信頼してください」などの言葉をよく耳にするかもしれません。抽象化レベルのため、実際の影響を測定することは実際には非常に困難です。プロファイルから実際のコストを収集するには、非常に時間がかかる可能性があり、抽象化のために非常に不正確です。同様に、ARC と MRC は大きな違いを生む可能性があります。
プロパティ アクセスの実装に焦点を当てるのではなく、一歩下がって、 のような通常の容疑者を含め、競合していないケース (秒単位の値) でのgetterobjc_msgSend
への多くの呼び出しについて、いくつかの現実世界の高レベルの結果を調べます。NSString
おそらくご想像のとおり、参照カウントのアクティビティ/サイクリングは、アトミックおよび ARC の下で重要な貢献者です。また、争われたケースではより大きな違いが見られます。
パフォーマンスには細心の注意を払っていますが、それでもセマンティクス ファーストと言っています。. 一方、パフォーマンスは多くのプロジェクトで優先度が低くなります。ただし、使用するテクノロジの実行の詳細とコストを知っていても、問題はありません。ニーズ、目的、能力に適したテクノロジーを使用する必要があります。うまくいけば、これにより数時間の比較を節約でき、プログラムを設計する際により良い情報に基づいた決定を下すことができます。
非常に多くの記事やスタック オーバーフローの投稿を読み、変数プロパティ属性をチェックするデモ アプリケーションを作成した後、すべての属性情報をまとめることにしました。
atomic
// デフォルトnonatomic
strong = retain
// デフォルトweak = unsafe_unretained
retain
assign
// デフォルトunsafe_unretained
copy
readonly
readwrite
// デフォルト記事Variable property attributes or modifiers in iOSでは、上記のすべての属性を見つけることができ、間違いなく役に立ちます。
atomic
atomic
1 つのスレッドのみが変数 (静的型) にアクセスすることを意味します。atomic
スレッドセーフです。atomic
はデフォルトの動作です例:
@property (retain) NSString *name;
@synthesize name;
nonatomic
nonatomic
複数のスレッドが変数 (動的型) にアクセスすることを意味します。nonatomic
スレッドセーフではありません。nonatomic
はデフォルトの動作ではありません。nonatomic
プロパティ属性にキーワードを追加する必要があります。例:
@property (nonatomic, retain) NSString *name;
@synthesize name;
ここで、原子と非原子のプロパティのかなり適切な説明を見つけました。これは、同じものからの関連テキストです。
「アトミック」とは、分解できないことを意味します。OS/プログラミングの用語では、アトミック関数呼び出しは中断できないものです。関数全体を実行する必要があり、完了するまで OS の通常のコンテキスト切り替えによって CPU からスワップアウトしないでください。ご存じないかもしれませんが、CPU は一度に 1 つのことしかできないため、OS は CPU へのアクセスを実行中のすべてのプロセスに小さなタイム スライスでローテーションさせて、錯覚を与えます。マルチタスクの。CPU スケジューラは、関数呼び出しの途中であっても、実行中の任意の時点でプロセスを中断できます (実際に中断します)。そのため、2 つのプロセスが同時に変数を更新しようとする可能性がある共有カウンター変数の更新などのアクションについては、それらを「アトミックに」実行する必要があります。 CPU。
したがって、この場合のアトミックとは、属性リーダーメソッドを中断できないことを意味すると推測します。つまり、メソッドによって読み取られる変数は、他のスレッド/呼び出し/関数が取得されるため、途中で値を変更できないことを意味します。 CPUにスワップしました。
変数は中断できないため、atomic
変数に含まれる値はいつでも (スレッドロック) 破損していないことが保証されますが、このスレッドロックを保証すると変数へのアクセスが遅くなります。non-atomic
一方、変数はそのような保証はありませんが、より迅速なアクセスという贅沢を提供します。要約するとnon-atomic
、変数が複数のスレッドによって同時にアクセスされないことがわかっている場合に使用して、速度を上げてください。
Atomicは、プロパティへのアクセスがアトミックな方法で実行されることを保証します。たとえば、常に完全に初期化されたオブジェクトを返します。あるスレッドのプロパティの取得/設定は、別のスレッドがアクセスする前に完了する必要があります。
次の関数が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とは異なり、完全に初期化されたオブジェクトが毎回返されることを保証するものではありません。
長所: 非常に高速な実行。
短所: マルチスレッドの場合のガベージ値の可能性。
最初の最も簡単な答え:2番目の2つの例に違いはありません。デフォルトでは、プロパティアクセサーはアトミックです。
ガベージコレクションされていない環境(つまり、保持/解放/自動解放を使用する場合)のアトミックアクセサーは、ロックを使用して、別のスレッドが値の正しい設定/取得に干渉しないようにします。
マルチスレッドアプリを作成する際の詳細およびその他の考慮事項については、AppleのObjective-C2.0ドキュメントの「パフォーマンスとスレッド」セクションを参照してください。
Atomic はスレッド セーフであり、低速であり、同じゾーンでアクセスを試みているスレッドの数に関係なく、ロックされた値のみが提供されることが保証されます(保証されません) 。アトミックを使用すると、この関数内に記述されたコードの一部がクリティカル セクションの一部になり、一度に 1 つのスレッドしか実行できなくなります。
スレッドの安全性を保証するだけです。ことを保証するものではありません。私が言いたいのは、あなたの車のために専門のドライバーを雇うということですが、それでも車が事故に遭わないという保証はありません。ただし、確率はごくわずかです。
Atomic - 分解できないため、結果が期待されます。非アトミック - 別のスレッドがメモリゾーンにアクセスすると、それが変更される可能性があるため、予期しない結果になります。
コードトーク:
プロパティのアトミックな getter と setter をスレッド セーフにします。たとえば、あなたが書いた場合:
self.myProperty = value;
スレッドセーフです。
[myArray addObject:@"Abc"]
スレッドセーフではありません。
アトミック (デフォルト)
アトミックがデフォルトです。何も入力しない場合、プロパティはアトミックです。アトミック プロパティは、読み込もうとすると有効な値が返されることが保証されています。その値が何であるかについて保証はしませんが、ジャンク メモリだけでなく、適切なデータが返されます。これにより、単一の変数を指す複数のスレッドまたは複数のプロセスがある場合、1 つのスレッドが読み取り、別のスレッドが書き込みを行うことができます。それらが同時にヒットした場合、リーダー スレッドは、変更前または変更後の 2 つの値のいずれかを取得することが保証されます。アトミックが提供しないのは、これらの値のどれが得られるかについての保証ではありません。Atomic はスレッドセーフであると混同されることがよくありますが、それは正しくありません。他の方法でスレッドの安全性を保証する必要があります。
非原子
反対に、非アトミックとは、おそらくご想像のとおり、「アトミックなことをしないでください」という意味です。あなたが失うものは、あなたが常に何かを取り戻すという保証です. 書き込みの途中で読み込もうとすると、ガベージ データが返される可能性があります。しかし、その一方で、あなたは少し速く進みます。アトミック プロパティは、値が返されることを保証するためにいくつかの魔法を実行する必要があるため、少し遅くなります。頻繁にアクセスするプロパティの場合は、非アトミックにドロップダウンして、速度が低下しないようにすることをお勧めします。
詳細はこちら: https://realm.io/news/tmi-objective-c-property-attributes/
「原子」というキーワードはありません
@property(atomic, retain) UITextField *userName;
上記のように使用できます
@property(retain) UITextField *userName;
@property(atomic,retain)NSString *myString を使用すると問題が発生するスタック オーバーフローの質問を参照してください。
デフォルトは です。atomic
これは、プロパティを使用するたびにパフォーマンスが低下することを意味しますが、スレッド セーフです。Objective-C が行うことは、ロックを設定することです。そのため、セッター/ゲッターが実行されている限り、実際のスレッドのみが変数にアクセスできます。
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;
最初のプロパティ属性としてキーワードを記述する必要はまったくありません。
これは、プロパティ全体がスレッドセーフであることを意味するものではないことを忘れないでください。セッター/ゲッターのメソッド呼び出しのみです。しかし、2 つの異なるスレッドで同時にセッターを使用し、その後ゲッターを使用すると、それも壊れる可能性があります。
宣言方法:
アトミックはデフォルトなので、
@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から "name" を呼び出すと、
と
同時に電話すると
[self setName:@"Datta"]
スレッドBから、
*name プロパティが非アトミックの場合
それが、非アトミックがスレッドアンセーフと呼ばれる理由ですが、並列実行のためにパフォーマンスが高速です
*name プロパティがアトミックの場合
それがアトミックがスレッドセーフと 呼ばれる理由であり、それが読み書きセーフと呼ばれる理由です。
このような状況の操作は、シリアルに実行されます。 そしてパフォーマンスが遅い
- 非アトミックとは、複数のスレッドが変数 (動的型) にアクセスすることを意味します。
- ノンアトミックはスレッドセーフではありません。
- ただし、パフォーマンスは高速です
-Nonatomic はデフォルトの動作ではありません。プロパティ属性に nonatomic キーワードを追加する必要があります。
For In Swift Swift プロパティが ObjC の意味で非アトミックであることを確認します。1 つの理由は、プロパティごとのアトミック性がニーズに十分かどうかを検討するためです。
参考:https ://forums.developer.apple.com/thread/25642
詳細については、Web サイトhttp://rdcworld-iphone.blogspot.in/2012/12/variable-property-attributes-or.htmlをご覧ください 。
マルチスレッド コードでプロパティを使用している場合は、非アトミック属性とアトミック属性の違いを確認できます。ノンアトミックはアトミックよりも高速で、アトミックは非アトミックではなくスレッドセーフです。
Vijayendra Tripathi は、すでにマルチスレッド環境の例を示しています。
アトミック プロパティは、ゲッターとセッターを実行しているスレッドの数に関係なく、完全に初期化された値を保持することを保証します。
非アトミック プロパティは、合成されたアクセサーが単に値を直接設定または返すことを指定し、同じ値が異なるスレッドから同時にアクセスされた場合に何が起こるかについての保証はありません。
アトミックとは、一度に 1 つのスレッドのみが変数にアクセスできることを意味します (静的型)。Atomic はスレッドセーフですが、遅いです。
非アトミックとは、複数のスレッドが同時に変数にアクセスできることを意味します (動的タイプ)。ノンアトミックはスレッドセーフではありませんが、高速です。
一行で:
Atomic
スレッドセーフです。Nonatomic
スレッドセーフではありません。
真実は、スピンロックを使用してアトミックプロパティを実装していることです。コードは次のとおりです。
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);
}
アトミックを使用している場合は、スレッドが安全で読み取り専用になることを意味します。非アトミックを使用している場合、複数のスレッドが変数にアクセスし、スレッドセーフではありませんが、高速に実行され、読み取り操作と書き込み操作が行われることを意味します。これは動的タイプです。
全体の混乱を単純化するために、mutex ロックについて理解しましょう。
ミューテックス ロックは、その名のとおり、オブジェクトの可変性をロックします。したがって、オブジェクトがクラスによってアクセスされる場合、他のクラスは同じオブジェクトにアクセスできません。
iOS@sychronise
では、ミューテックス ロックも提供します。現在は FIFO モードで機能し、同じインスタンスを共有する 2 つのクラスによってフローが影響を受けないようにします。ただし、タスクがメイン スレッド上にある場合は、アトミック プロパティを使用してオブジェクトにアクセスしないようにしてください。UI が保持され、パフォーマンスが低下する可能性があるためです。
アトミック: NSLOCK を使用してスレッドをロックすることにより、スレッド セーフを確保します。
非アトミック: スレッド ロック メカニズムがないため、スレッド セーフは保証されません。