ios - 原子和非原子属性之间的区别是什么?

  显示原文与译文双语对照的内容

atomicnonatomic 在属性声明中的含义?


@property(nonatomic, retain) UITextField *userName;
@property(atomic, retain) UITextField *userName;
@property(retain) UITextField *userName;

这三者之间的操作差异是什么?

时间:

最后两个是相同的;"原子"是默认行为( 注意它实际上不是关键字;它只由没有 nonatomic 指定 在最近的llvm/clang版本中添加了 -- atomic 作为关键字。

假设你是 @synthesizing 方法实现,原子 vs non-atomic会更改生成的代码。 如果你正在编写自己的setter/getter,atomic/nonatomic/retain/assign/copy 只是一个建议。 ( 注意:@synthesize 现在是最近版本的LLVM的默认行为) 。 也不需要声明实例变量;它们也将被自动合成,并且将有一个 _ 前的名称以防止意外直接访问。

对任何其他与"原子"thread,,所合成的setter/getter将确保一个整个总是从第一次访问它时返回或者设置该值的设置器,而不考虑设置器的活动区域, 也就是说,如果一个处于中间的获取方法,而线程B 线程调用set访问器,则实际可行的值--一个极有可能 -- autoreleased对象将被返回给调用者在一个。

nonatomic 中,没有这样的保证。 因此,nonatomic 比"原子"快得多。

"原子"确实做的就是做出任何担保有关线程安全的内容。 B 和c,如果线程中使用不同的值一个是同时调用获取方法与线程B 和C 调用设置器,穿好可能得到任何返回--了这三个值中的一个一个执行任何setter方法被调用之前的最大值或者最小值的值传递到 setters. 同样的,对象可能会得到来自或者C的值,无法分辨。

确保数据完整性--是multi-threaded编程--的主要挑战之一是通过其他方法实现的。

这是在下面的苹果文档,但是解释恶化的情况实际发生了什么。 注意,没有"原子"关键字,如果你没有指定"无上下文",那么属性是原子的,但是显式指定"原子"会导致错误。


//@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 release];
 userName = [userName_ retain];
 }
}

基本上,必须采用锁的原子版本为了保证线程不安全,同时也是撞上的ref计数为调用方,否则会有( autorelease计数来平衡它),以便对象是保证存在于一个潜在的竞争条件如果另一个线程将该值设置,导致了ref计数要减到 0.

根据属性是标量值还是对象,以及如何保留,复制,只读,无安全等,这些事情实际上有大量不同的变体。 一般来说,属性合成器只知道如何为所有组合执行"正确的事情"。

后期响应程序- 语法和语义已经被这个问题的其他优秀的答案所定义。 因为执行和 性能不详细哦,我将添加我的答案。

这些 3之间的功能差异是什么?

我一直认为原子是一个非常有趣的。 我们在抽象级别上工作,使用原子类将事件作为车辆的属性,以达到 100% thread-safety是一种特殊情况。 对于真正正确的多线程程序,程序员的干预几乎是一个需求。 同时,性能特征和执行还没有深入的深入。 于任何purpose,让写了一些相关大量多线程程序多年来,我一直都在我的属性声明为原子不是 sensible. nonatomic 整个时间,因为 在讨论原子和非原子属性的细节时这个问题,我做了一些分析,遇到一些奇怪的结果。

执行

首先,我想澄清的是,锁定实现是定义和抽象的实现。 路易使用 @synchronized(self) --我曾见过他的示例中作为常见的引起混乱。 实际上的实现不 使用 @synchronized(self) ;它使用对象级别 自旋锁。 路易却是致命的高水平的插图插图使用构造了我们都很熟悉,但有必要知道它不使用 @synchronized(self)

另一个区别是原子属性将保留/释放在getter中的对象。

性能

无争用 ( 例如 g, accesses.这里的有趣的部分即绩效用原子属性 single-threaded ) 案例在某些情况下可能非常快。 在不到理想的情况下,请使用原子访问的可以超过 20成本乘以 nonatomic的开销。 于时 3字节 struct 受争议的情况下不必使用 7线程是 44时报相关 slower. 3字节结构是一个非常慢的属性的示例。

有趣的struct were 52 times faster than the synthesized atomic accessors; 或者 84% 3字节的速度合成了非原子的边注:User-defined访问器访问器。

争用案例中的对象也可以超过 50次。

由于实现的优化和变化的数量,在这些上下文中衡量真实世界的影响是相当困难的。 你可能会听到类似"相信它,除非你发现并发现它是一个问题"的东西。 由于抽象级别,实际上很难衡量实际的影响。 从配置文件获取实际成本可能非常耗时,而且由于抽象,非常不准确。 同样,ARC vs MRC会产生很大的差异。

在无争用情况下所以我们退后一步,在实施物业访问,我们将包括普通疑点像 objc_msgSend 不专注于对现实世界,并查看一些高级结果对于许多呼叫 NSString getter:

  • MRC | 无上下文| 手动实现的getter: 2
  • MRC | 无上下文| 合成 getter: 7
  • MRC | 原子| 合成 getter: 47
  • ARC | 无参数| 合成 getter: 38 ( 注意:在这里添加圆弧计数计数循环)
  • 弧| 原子| 合成 getter: 47

你可能已经猜到了,引用计数活动/循环是原子和在ARC下的重要贡献者。 你也会看到在争议案例中的差异较大。

虽然我先请特别注意性能,我还是说语义 ! 同时,性能对于许多项目来说都是一个低优先级。 然而,知道你使用的技术的细节和成本当然不会伤害你。 你应该为你的需求,目的和能力使用正确的技术。 希望这会节省你几个小时的比较,并帮助你在设计程序时做出更好的决策。

原子

  • 是默认行为
  • 将确保当前进程由cpu完成,在另一个进程访问变量之前
  • 不快速,因为它确保进程完全完成

Non-Atomic

  • 不是默认行为
  • 使用 @property, @synthesize ),更快( 用于合成生成码,IE 可以变量
  • 不是线程安全
  • 当两个不同的进程同时访问同一个变量时,可能会导致意外的行为

最好的方法是理解差异,使用以下示例。 假设有一个名为"姓名"的原子字符串属性,如果你从线程 [self setName:@"A"] 调用,则从线程B 调用 [self setName:@"B"],并从线程C 调用 [self name],线程将执行setter或者 getter,然后其他线程将等待。 这使得属性"姓名"读/写安全,但是如果另一个线程调用 [name release],那么这个操作可能会产生崩溃,因为这里没有 setter/getter调用。 这意味着一个对象是读取/写入安全的( 原子),而不是线程安全的,因为另一个线程可以同时向对象发送任何类型的消息。 开发者应该确保这些对象的线程安全。

如果属性"姓名"是非静态的,那么上面示例中的所有线程- A,B,C 和D 将同时执行,产生任何不可预测的结果。 在原子中,任何一个,B 或者C 都会先执行,但仍然可以并行执行。 希望这有帮助

最简单的回答:你的第二个例子没有区别。 默认情况下,属性访问器是原子的。

非垃圾收集环境中的原子访问器( 例如 。 使用 retain/release/autorelease) 时,将使用锁确保另一个线程不会干扰正确的设置/获取值。

请参阅苹果 2.0 objective-c"性能和线程编辑器"一节中的文档以了解更多的资料及用于其他注意事项在创建multi-threaded应用。

我在这里找到了一个非常好的原子和non-atomic属性的解释 下面是一些相关的文本:

''原子'意味着它不能破坏掉。 在操作系统/编程术语中,原子函数调用是一个不能被中断的函数。整个函数必须被执行,并且通常由操作系统上下文切换来完成,直到它完成。 以防你不知道: 因为CPU一次只能做一件事情,这个操作系统中所有运行的进程对CPU的访问旋转至少 time-slices,为给错觉的的多任务。 CPU调度程序可以在执行过程中随时中断进程- 即使在mid函数调用中。 因此,对于更新共享计数器变量( 在两个进程可以同时更新变量的情况下),它们必须执行'原子的',换句话说,每个更新操作都必须在任何其他进程交换到CPU之前完成。

因此,我猜想这种情况下的原子意味着属性读取器方法不能被中断- 实际上意味着通过方法读取的变量不能改变它的值,因为其他 thread/call/function 被交换到 CPU 。

因为 atomic 变量都不能中断,它们所包含的值在任何时候是( thread-lock ) 保证是未被破坏的,虽然对他们作出访问较慢,确保该线程锁。 另一方面,non-atomic 变量不保证这样的保证,但它提供了更快速的访问。 总而言之,当你知道你的变量不会被多个线程同时访问并加快速度时,使用 non-atomic

原子 = 线程安全

Non-atomic = 无线程安全

线程安全:

实例varialbe在从多个线程访问时,如果运行时环境的调度或者交错运行,或者在调用代码中没有额外的同步或者其他协调,那么它是 thread-safe

在我们的上下文中:

如果一个线程更改了实例的值,更改的值对所有线程都可用

一次只能有一个线程更改该值。

在哪里使用原子:

如果在多线程环境中访问实例变量

原子的含义:

不像原子bcuz无传感器那样,在运行时不需要任何监视狗

在哪里使用非原子:

如果实例变量不能被多个线程更改,那么可以使用 this.it 改进性能

阅读了这么多文章之后,文章和制作了演示应用来检查变量属性属性,我决定把所有的属性信息放在一起

  1. 原子//default
  2. 无上下文
  3. strong=retain//default
  4. weak= unsafe_unretained
  5. 保留
  6. 指派//default
  7. unsafe_unretained
  8. 副本
  9. 只读
  10. 读写//default

下面是详细的文章链接,你可以在上面找到上面提到的所有属性,这将defiantly帮助你。 感谢所有在这里给出最佳答案的人 !

在网路作业系统, 变量属性属性或者修饰符

01.原子 - 原子意味着只有一个线程访问 variable(static type) 。 - 原子是线程安全的。 - 但性能缓慢- 原子是默认行为- 非垃圾收集环境中的原子访问器( 例如 。 使用 retain/release/autorelease) 时,将使用锁确保另一个线程不会干扰正确的设置/获取值。 - 它不是一个关键字。

例如:


@property (retain) NSString *name;

@synthesize name;

02.无原子 - 非原子意味着多个线程访问 variable(dynamic type) 。 - 非安全线程不安全。 - 但这是快速在性能- 无原子不是默认行为,我们需要添加非原子c 语言中属性的属性。 - 当两个不同的进程( 线程) 同时访问同一个变量时,它可能会导致意外的行为。

例如:


@property (nonatomic, retain) NSString *name;

@synthesize name;

原子保证对属性的访问将以原子方式执行。 比如 将是线程安全的,任何一个线程上的任何获取/设置属性都必须完成才能访问它。

如果你想象一下以下的函数在两个线程上发生,你可以看到为什么结果不会很好。


-(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;
 }

. . .
}

...