ios 原子属性和非原子属性有什么区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/588866/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What's the difference between the atomic and nonatomic attributes?
提问by Alex Wayne
What do atomic
and nonatomic
mean in property declarations?
什么atomic
和nonatomic
财产申报是什么意思?
@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;
What is the operational difference between these three?
这三者的操作区别是什么?
采纳答案by bbum
The last two are identical; "atomic" is the default behavior (note that it is not actually a keyword; it is specified only by the absence of -- nonatomic
atomic
was added as a keyword in recent versions of llvm/clang).
最后两个是相同的;“原子”是默认行为(请注意,它实际上不是关键字;它仅通过缺少--nonatomic
atomic
在最近版本的 llvm/clang 中被添加为关键字来指定)。
Assuming that you are @synthesizing the method implementations, atomic vs. non-atomic changes the generated code. If you are writing your own setter/getters, atomic/nonatomic/retain/assign/copy are merely advisory. (Note: @synthesize is now the default behavior in recent versions of LLVM. There is also no need to declare instance variables; they will be synthesized automatically, too, and will have an _
prepended to their name to prevent accidental direct access).
假设您正在@synthesizing 方法实现,原子与非原子会更改生成的代码。如果您正在编写自己的 setter/getter,原子/非原子/保留/分配/复制仅仅是建议性的。(注意:@synthesize 现在是 LLVM 最新版本中的默认行为。也不需要声明实例变量;它们也会被自动合成,并且会_
在它们的名称前加上一个前缀以防止意外的直接访问)。
With "atomic", the synthesized setter/getter will ensure that a wholevalue is always returned from the getter or set by the setter, regardless of setter activity on any other thread. That is, if thread A is in the middle of the getter while thread B calls the setter, an actual viable value -- an autoreleased object, most likely -- will be returned to the caller in A.
使用“原子”,合成的 setter/getter 将确保始终从 getter 返回或由 setter 设置整个值,而不管任何其他线程上的 setter 活动如何。也就是说,如果线程 A 在 getter 的中间,而线程 B 调用 setter,则一个实际可行的值——一个自动释放的对象,最有可能——将返回给 A 中的调用者。
In nonatomic
, no such guarantees are made. Thus, nonatomic
is considerably faster than "atomic".
在 中nonatomic
,没有做出这样的保证。因此,nonatomic
比“原子”快得多。
What "atomic" does notdo is make any guarantees about thread safety. If thread A is calling the getter simultaneously with thread B and C calling the setter with different values, thread A may get any one of the three values returned -- the one prior to any setters being called or either of the values passed into the setters in B and C. Likewise, the object may end up with the value from B or C, no way to tell.
什么“原子”并没有做的就是关于线程安全任何保证。如果线程 A 在调用 getter 的同时,线程 B 和 C 使用不同的值调用 setter,则线程 A 可能会获得返回的三个值中的任何一个——调用任何 setter 之前的值或传递给 setter 的值之一在 B 和 C 中。同样,对象可能以来自 B 或 C 的值结束,无法分辨。
Ensuring data integrity -- one of the primary challenges of multi-threaded programming -- is achieved by other means.
确保数据完整性——多线程编程的主要挑战之一——是通过其他方式实现的。
Adding to this:
添加到此:
atomicity
of a single property also cannot guarantee thread safety when multiple dependent properties are in play.
atomicity
当多个依赖属性在起作用时,单个属性也不能保证线程安全。
Consider:
考虑:
@property(atomic, copy) NSString *firstName;
@property(atomic, copy) NSString *lastName;
@property(readonly, atomic, copy) NSString *fullName;
In this case, thread A could be renaming the object by calling setFirstName:
and then calling setLastName:
. In the meantime, thread B may call fullName
in between thread A's two calls and will receive the new first name coupled with the old last name.
在这种情况下,线程 A 可以通过调用setFirstName:
然后调用来重命名对象setLastName:
。同时,线程 B 可能会fullName
在线程 A 的两次调用之间进行调用,并且会收到新的名字和旧的姓氏。
To address this, you need a transactional model. I.e. some other kind of synchronization and/or exclusion that allows one to exclude access to fullName
while the dependent properties are being updated.
为了解决这个问题,您需要一个事务模型。即某种其他类型的同步和/或排除允许fullName
在更新依赖属性时排除访问。
回答by Louis Gerbarg
This is explained in Apple's documentation, but below are some examples of what is actually happening.
这在 Apple 的文档中进行了解释,但下面是一些实际发生的情况的示例。
Note that there is no "atomic" keyword, if you do not specify "nonatomic", then the property is atomic, but specifying "atomic" explicitly will result in an error.
注意这里没有“atomic”关键字,如果不指定“nonatomic”,则属性是atomic,但明确指定“atomic”会报错。
If you do not specify "nonatomic", then the property is atomic, but you can still specify "atomic" explicitly in recent versions if you want to.
如果您不指定“非原子”,则该属性是原子的,但如果您愿意,您仍然可以在最近的版本中明确指定“原子”。
//@property(nonatomic, retain) UITextField *userName;
//Generates roughly
- (UITextField *) userName {
return userName;
}
- (void) setUserName:(UITextField *)userName_ {
[userName_ retain];
[userName release];
userName = userName_;
}
Now, the atomic variant is a bit more complicated:
现在,原子变体有点复杂:
//@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_;
}
}
Basically, the atomic version has to take a lock in order to guarantee thread safety, and also is bumping the ref count on the object (and the autorelease count to balance it) so that the object is guaranteed to exist for the caller, otherwise there is a potential race condition if another thread is setting the value, causing the ref count to drop to 0.
基本上,原子版本必须锁定以保证线程安全,并且还会增加对象上的引用计数(以及自动释放计数以平衡它),以便保证调用者存在该对象,否则有如果另一个线程正在设置该值,则是潜在的竞争条件,导致引用计数降至 0。
There are actually a large number of different variants of how these things work depending on whether the properties are scalar values or objects, and how retain, copy, readonly, nonatomic, etc interact. In general the property synthesizers just know how to do the "right thing" for all combinations.
实际上,根据属性是标量值还是对象,以及保留、复制、只读、非原子等交互方式,这些事物的工作方式有很多不同的变体。一般来说,属性合成器只知道如何为所有组合做“正确的事情”。
回答by raw3d
Atomic
原子
- is the default behavior
- will ensure the present process is completed by the CPU, before another process accesses the variable
- is not fast, as it ensures the process is completed entirely
- 是默认行为
- 将确保当前进程由 CPU 完成,然后另一个进程访问该变量
- 不快,因为它确保过程完全完成
Non-Atomic
非原子
- is NOT the default behavior
- faster (for synthesized code, that is, for variables created using @property and @synthesize)
- not thread-safe
- may result in unexpected behavior, when two different process access the same variable at the same time
- 不是默认行为
- 更快(对于合成代码,即使用@property 和@synthesize 创建的变量)
- 不是线程安全的
- 当两个不同的进程同时访问同一个变量时,可能会导致意外行为
回答by Vijayendra
The best way to understand the difference is using the following example.
了解差异的最佳方法是使用以下示例。
Suppose there is an atomic string property called "name", and if you call [self setName:@"A"]
from thread A, call [self setName:@"B"]
from thread B, and call [self name]
from thread C, then all operations on different threads will be performed serially which means if one thread is executing a setter or getter, then other threads will wait.
假设有一个名为“name”的原子字符串属性,如果你[self setName:@"A"]
从线程 A 调用,[self setName:@"B"]
从线程 B 调用,[self name]
从线程 C调用,那么不同线程上的所有操作都将串行执行,这意味着如果一个线程正在执行 setter或 getter,然后其他线程将等待。
This makes property "name" read/write safe, but if another thread, D, calls [name release]
simultaneously then this operation might produce a crash because there is no setter/getter call involved here. Which means an object is read/write safe (ATOMIC), but not thread-safe as another threads can simultaneously send any type of messages to the object. The developer should ensure thread-safety for such objects.
这使得属性“name”读/写安全,但如果另一个线程 D[name release]
同时调用,则此操作可能会导致崩溃,因为此处不涉及 setter/getter 调用。这意味着一个对象是读/写安全 (ATOMIC),但不是线程安全的,因为另一个线程可以同时向该对象发送任何类型的消息。开发人员应确保此类对象的线程安全。
If the property "name" was nonatomic, then all threads in above example - A,B, C and D will execute simultaneously producing any unpredictable result. In case of atomic, either one of A, B or C will execute first, but D can still execute in parallel.
如果属性“name”是非原子的,那么上例中的所有线程——A、B、C 和 D 将同时执行,产生任何不可预测的结果。在原子的情况下,A、B 或 C 中的任何一个将首先执行,但 D 仍然可以并行执行。
回答by justin
The syntax and semantics are already well-defined by other excellent answers to this question. Because executionand performanceare not detailed well, I will add my answer.
这个问题的其他优秀答案已经很好地定义了语法和语义。由于执行和性能没有详细说明,我将添加我的答案。
What is the functional difference between these 3?
这三个之间的功能区别是什么?
I'd always considered atomic as a default quite curious. At the abstraction level we work at, using atomic properties for a class as a vehicle to achieve 100% thread-safety is a corner case. For truly correct multithreaded programs, intervention by the programmer is almost certainly a requirement. Meanwhile, performance characteristics and execution have not?yet been detailed in depth. Having written some heavily multithreaded programs over the years, I had been declaring my properties as nonatomic
the entire time because atomic was not sensible for any purpose. During discussion of the details of atomic and nonatomic properties this question, I did some profiling encountered some curious results.
我一直认为 atomic 作为默认设置非常好奇。在我们工作的抽象级别,使用类的原子属性作为工具来实现 100% 线程安全是一种极端情况。对于真正正确的多线程程序,几乎可以肯定需要程序员的干预。同时,性能特征和执行还没有深入详述。多年来编写了一些多线程程序,我一直在声明我的属性,nonatomic
因为原子对于任何目的都是不合理的。在讨论原子和非原子属性这个问题的细节时,我做了一些分析,遇到了一些奇怪的结果。
Execution
执行
Ok. The first thing I would like to clear up is that the locking implementation is implementation-defined and abstracted. Louis uses @synchronized(self)
in his example -- I have seen this as a common source of confusion. The implementation does not actuallyuse @synchronized(self)
; it uses object level spin locks. Louis's illustration is good for a high-level illustration using constructs we are all familiar with, but it's important to know it does not use @synchronized(self)
.
好的。我想澄清的第一件事是锁定实现是实现定义和抽象的。路易斯@synchronized(self)
在他的例子中使用了——我认为这是一个常见的混淆来源。该实现实际上并没有使用@synchronized(self)
; 它使用对象级自旋锁。Louis 的插图适用于使用我们都熟悉的结构的高级插图,但重要的是要知道它不使用@synchronized(self)
.
Another difference is that atomic properties will retain/release cycle your objects within the getter.
另一个区别是原子属性将在 getter 中保留/释放循环您的对象。
Performance
表现
Here's the interesting part: Performance using atomic property accesses in uncontested(e.g. single-threaded) cases can be really very fast in some cases. In less than ideal cases, use of atomic accesses can cost more than 20 times the overhead of nonatomic
. While the Contestedcase using 7 threads was 44 times slower for the three-byte struct (2.2 GHz Core i7Quad Core, x86_64). The three-byte struct is an example of a very slow property.
这是有趣的部分:在某些情况下,在无争议(例如单线程)情况下使用原子属性访问的性能可能非常快。在不太理想的情况下,使用原子访问的开销可能是 的 20 倍以上nonatomic
。而使用 7 个线程的Contested案例对于三字节结构(2.2 GHz Core i7Quad Core,x86_64)来说要慢 44 倍。三字节结构体是一个非常慢的属性的例子。
Interesting side note: User-defined accessors of the three-byte struct were 52 times faster than the synthesized atomic accessors; or 84% the speed of synthesized nonatomic accessors.
有趣的旁注:三字节结构的用户定义访问器比合成原子访问器快 52 倍;或 84% 的合成非原子存取器的速度。
Objects in contested cases can also exceed 50 times.
有争议的案件中的对象也可以超过50次。
Due to the number of optimizations and variations in implementations, it's quite difficult to measure real-world impacts in these contexts. You might often hear something like "Trust it, unless you profile and find it is a problem". Due to the abstraction level, it's actually quite difficult to measure actual impact. Gleaning actual costs from profiles can be very time consuming, and due to abstractions, quite inaccurate. As well, ARC vs MRC can make a big difference.
由于实现中的优化和变化的数量,在这些环境中衡量现实世界的影响非常困难。您可能经常听到类似“相信它,除非您分析并发现它有问题”之类的内容。由于抽象级别,实际上很难衡量实际影响。从配置文件中收集实际成本可能非常耗时,并且由于抽象,非常不准确。同样,ARC 与 MRC 可以产生很大的不同。
So let's step back, notfocussing on the implementation of property accesses, we'll include the usual suspects like objc_msgSend
, and examine some real-world high-level results for many calls to a NSString
getter in uncontestedcases (values in seconds):
因此,让我们退后一步,不关注属性访问的实现,我们将包括常见的可疑对象,例如objc_msgSend
,并检查NSString
在无争议情况下对getter 的许多调用的一些真实世界的高级结果(以秒为单位的值):
- MRC | nonatomic | manually implemented getters: 2
- MRC | nonatomic | synthesized getter: 7
- MRC | atomic | synthesized getter: 47
- ARC | nonatomic | synthesized getter: 38 (note: ARC's adding ref count cycling here)
- ARC | atomic | synthesized getter: 47
- MRC | 非原子 | 手动实现的吸气剂:2
- MRC | 非原子 | 合成吸气剂:7
- MRC | 原子 | 合成吸气剂:47
- 弧 | 非原子 | 合成的 getter:38(注意:ARC 在此处添加引用计数循环)
- 弧 | 原子 | 合成吸气剂:47
As you have probably guessed, reference count activity/cycling is a significant contributor with atomics and under ARC. You would also see greater differences in contested cases.
正如您可能已经猜到的那样,引用计数活动/循环是原子和 ARC 下的重要贡献者。您还会在有争议的案例中看到更大的差异。
Although I pay close attention to performance, I still say Semantics First!. Meanwhile, performance is a low priority for many projects. However, knowing execution details and costs of technologies you use certainly doesn't hurt. You should use the right technology for your needs, purposes, and abilities. Hopefully this will save you a few hours of comparisons, and help you make a better informed decision when designing your programs.
虽然我很关注性能,但我还是说语义优先!. 同时,性能对于许多项目来说是次要的。但是,了解您使用的技术的执行细节和成本当然不会有什么坏处。您应该根据自己的需求、目的和能力使用正确的技术。希望这将为您节省几个小时的比较时间,并帮助您在设计程序时做出更明智的决定。
回答by Durai Amuthan.H
Atomic= thread safety
原子= 线程安全
Non-atomic= No thread safety
非原子= 没有线程安全
Thread safety:
线程安全:
Instance variables are thread-safe if they behave correctly when accessed from multiple threads, regardless of the scheduling or interleaving of the execution of those threads by the runtime environment, and with no additional synchronization or other coordination on the part of the calling code.
如果实例变量在从多个线程访问时行为正确,则它们是线程安全的,无论运行时环境对这些线程的执行进行调度或交错,并且调用代码部分没有额外的同步或其他协调。
In our context:
在我们的上下文中:
If a thread changes the value of the instance the changed value is available to all the threads, and only one thread can change the value at a time.
如果一个线程更改了实例的值,则更改后的值可用于所有线程,并且一次只有一个线程可以更改该值。
Where to use atomic
:
在哪里使用atomic
:
if the instance variable is gonna be accessed in a multithreaded environment.
如果要在多线程环境中访问实例变量。
Implication of atomic
:
的含义atomic
:
Not as fast as nonatomic
because nonatomic
doesn't require any watchdog work on that from runtime .
没有那么快,nonatomic
因为nonatomic
从运行时不需要任何看门狗工作。
Where to use nonatomic
:
在哪里使用nonatomic
:
If the instance variable is not gonna be changed by multiple threads you can use it. It improves the performance.
如果实例变量不会被多个线程更改,您可以使用它。它提高了性能。
回答by tipycalFlow
I found a pretty well put explanation of atomic and non-atomic properties here. Here's some relevant text from the same:
我发现原子和非原子性的一个很好的解释放在这里。下面是一些相关的文本:
'atomic' means it cannot be broken down. In OS/programming terms an atomic function call is one that cannot be interrupted - the entire function must be executed, and not swapped out of the CPU by the OS's usual context switching until it's complete. Just in case you didn't know: since the CPU can only do one thing at a time, the OS rotates access to the CPU to all running processes in little time-slices, to give the illusionof multitasking. The CPU scheduler can (and does) interrupt a process at any point in its execution - even in mid function call. So for actions like updating shared counter variables where two processes could try to update the variable at the same time, they must be executed 'atomically', i.e., each update action has to finish in its entirety before any other process can be swapped onto the CPU.
So I'd be guessing that atomic in this case means the attribute reader methods cannot be interrupted - in effect meaning that the variable(s) being read by the method cannot change their value half way through because some other thread/call/function gets swapped onto the CPU.
“原子”意味着它不能被分解。在操作系统/编程术语中,原子函数调用是不能被中断的——整个函数必须被执行,并且在完成之前不能通过操作系统的通常上下文切换从 CPU 中换出。以防万一您不知道:由于 CPU 一次只能做一件事,因此操作系统会在很小的时间片内将 CPU 的访问权轮流到所有正在运行的进程,以给人一种错觉的多任务处理。CPU 调度程序可以(并且确实)在其执行过程中的任何时候中断进程——即使是在函数调用中间。因此,对于更新共享计数器变量之类的操作,其中两个进程可以尝试同时更新变量,它们必须“以原子方式”执行,即,每个更新操作必须完整完成,然后才能将任何其他进程交换到中央处理器。
所以我猜在这种情况下原子意味着属性读取器方法不能被中断 - 实际上意味着该方法读取的变量不能在中途更改它们的值,因为其他一些线程/调用/函数得到交换到 CPU 上。
Because the atomic
variables can not be interrupted, the value contained by them at any point is (thread-lock) guaranteed to be uncorrupted, although, ensuring this thread lock makes access to them slower. non-atomic
variables, on the other hand, make no such guarantee but do offer the luxury of quicker access. To sum it up, go with non-atomic
when you know your variables won't be accessed by multiple threads simultaneously and speed things up.
因为atomic
变量不能被中断,所以它们在任何时候包含的值(线程锁)都保证是未损坏的,尽管确保此线程锁会使访问它们的速度变慢。non-atomic
另一方面,变量并没有做出这样的保证,但确实提供了更快访问的奢侈。总而言之,non-atomic
当您知道多个线程不会同时访问您的变量并加快速度时,请继续使用。
回答by swiftBoy
After reading so many articles, Stack Overflow posts and making demo applications to check variable property attributes, I decided to put all the attributes information together:
看了这么多文章,Stack Overflow 发帖,做了demo应用来检查变量属性的属性,我决定把所有的属性信息放在一起:
atomic
// Defaultnonatomic
strong = retain
// Defaultweak = unsafe_unretained
retain
assign
// Defaultunsafe_unretained
copy
readonly
readwrite
// Default
atomic
// 默认nonatomic
strong = retain
// 默认weak = unsafe_unretained
retain
assign
// 默认unsafe_unretained
copy
readonly
readwrite
// 默认
In the article Variable property attributes or modifiers in iOSyou can find all the above-mentioned attributes, and that will definitely help you.
在iOS 中的变量属性属性或修饰符一文中,您可以找到所有上述属性,这肯定会对您有所帮助。
atomic
atomic
means only one thread access the variable (static type).atomic
is thread safe.- But it is slow in performance
atomic
is the default behavior- Atomic accessors in a non garbage collected environment (i.e. when using retain/release/autorelease) will use a lock to ensure that another thread doesn't interfere with the correct setting/getting of the value.
- It is not actually a keyword.
Example:
@property (retain) NSString *name; @synthesize name;
nonatomic
nonatomic
means multiple thread access the variable (dynamic type).nonatomic
is thread-unsafe.- But it is fast in performance
nonatomic
is NOT default behavior. We need to add thenonatomic
keyword in the property attribute.- It may result in unexpected behavior, when two different process (threads) access the same variable at the same time.
Example:
@property (nonatomic, retain) NSString *name; @synthesize name;
atomic
atomic
意味着只有一个线程访问变量(静态类型)。atomic
是线程安全的。- 但它的性能很慢
atomic
是默认行为- 非垃圾收集环境中的原子访问器(即使用保留/释放/自动释放时)将使用锁来确保另一个线程不会干扰值的正确设置/获取。
- 它实际上不是关键字。
例子:
@property (retain) NSString *name; @synthesize name;
nonatomic
nonatomic
表示多线程访问变量(动态类型)。nonatomic
是线程不安全的。- 但它的性能很快
nonatomic
不是默认行为。我们需要nonatomic
在属性属性中添加关键字。- 当两个不同的进程(线程)同时访问同一个变量时,可能会导致意外行为。
例子:
@property (nonatomic, retain) NSString *name; @synthesize name;
回答by Andrew Grant
Atomic :
原子:
Atomic guarantees that access to the property will be performed in an atomic manner. E.g. it always return a fully initialised objects, any get/set of a property on one thread must complete before another can access it.
Atomic 保证对属性的访问将以原子方式执行。例如,它总是返回一个完全初始化的对象,一个线程上的属性的任何获取/设置必须在另一个线程访问它之前完成。
If you imagine the following function occurring on two threads at once you can see why the results would not be pretty.
如果您想象以下函数同时发生在两个线程上,您就会明白为什么结果不会很漂亮。
-(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;
}
...
}
Pros :Return of fully initialised objects each time makes it best choice in case of multi-threading.
优点:每次返回完全初始化的对象是多线程情况下的最佳选择。
Cons :Performance hit, makes execution a little slower
缺点:性能下降,使执行速度变慢
Non-Atomic :
非原子:
Unlike Atomic, it doesn't ensure fully initialised object return each time.
与 Atomic 不同,它不能确保每次都返回完全初始化的对象。
Pros :Extremely fast execution.
优点:执行速度极快。
Cons :Chances of garbage value in case of multi-threading.
缺点:多线程情况下可能会产生垃圾值。
回答by Jay O'Conor
Easiest answer first: There's no difference between your second two examples. By default, property accessors are atomic.
首先最简单的答案:您的后两个示例之间没有区别。默认情况下,属性访问器是原子的。
Atomic accessors in a non garbage collected environment (i.e. when using retain/release/autorelease) will use a lock to ensure that another thread doesn't interfere with the correct setting/getting of the value.
非垃圾收集环境中的原子访问器(即使用保留/释放/自动释放时)将使用锁来确保另一个线程不会干扰值的正确设置/获取。
See the "Performance and Threading" section of Apple's Objective-C 2.0 documentation for some more information and for other considerations when creating multi-threaded apps.
有关更多信息和创建多线程应用程序时的其他注意事项,请参阅Apple 的 Objective-C 2.0 文档的“性能和线程”部分。