关于iOS:什么时候我不能使用原子属性?

When can I not use atomic properties?

本问题已经有最佳答案,请猛点这里访问。

我知道有关于原子答案和非原子答案的答案,但它们大多看起来相当古老(2011年和更早),所以我希望得到最新的建议。我的理解是,非原子属性更快,但线程不安全。这是否意味着可以同时从多个线程访问的任何属性都应该是原子的?有没有条件可以使它成为非原子的?在决定是使一个属性成为原子的还是非原子的过程中,还有什么其他的关注呢?


声明属性atomic使编译器生成额外的代码,以防止对该属性的并发访问。这个额外的代码锁定信号量,然后获取或设置属性,然后解锁信号量。与设置或获取原语值或指针相比,锁定和解锁信号量的成本很高(尽管考虑到应用程序的整体流程,通常可以忽略不计)。

由于大多数IOS下的类,特别是与UI相关的类,将在单线程环境中使用,因此可以安全地删除atomic(即写入nonatomic,因为默认情况下属性是atomic),即使操作相对便宜,也不想为不需要的东西付费。


在大多数情况下,属性在多线程环境中是否为原子属性并不重要。

什么?

在大多数情况下,属性在多线程环境中是否为原子属性并不重要。

这样做的原因是,通过打开原子性使属性"线程安全"不会使代码线程安全。要得到这个,您需要做更多的工作,而这个工作通常会隐式地确保属性不被并行访问。

让我们举个例子:有一个类Person,它的属性firstNamelastName都是NSString*的。您只需添加用空格分隔的两个名称,就可以得到完整的名称。

1
NSString *fullName = [NSString stringWithFormat:@"%@ %@", person.firstName, person.lastName];

您知道其他线程可以在您执行此操作时更新属性。使属性具有原子性并没有任何帮助。如果人们的姓氏在读了名字之后,但在读了第二个名字之前发生了变化,这没有帮助。如果在计算全名后更改了人员的姓名,这没有帮助,因为这在下一刻可能无效。

您必须序列化操作,而不是属性访问。但是原子性只序列化访问。因此,如果至少有一个操作具有多个访问权限,那么它就没有帮助。所有病例的99999999 373%。

忘记属性原子性。这是毫无意义的。


将属性声明为原子属性不一定使其线程安全。

原子是默认的,与非原子相比,它需要一些额外的开销。如果线程A在该属性的getter的中途,而线程B更改了setter中的值,那么使用atomic将确保从getter返回一个可行的完整值。如果使用非原子,则不会生成额外的代码,因此非原子速度更快。

但是,这并不能保证螺纹安全。如果线程A调用getter,而线程B和C正在用不同的值更新线程,那么线程A可以获取任意一个值,并且不能保证它将获得哪个值。

为了具体地回答您的问题,许多场景都允许非原子属性,如果不是大多数的话。尽管使用原子的额外开销可能是可以忽略的。简单地说,您的属性是在不同的线程上读取还是设置的?如果不是,您很可能不需要将它们声明为原子的,但是额外的开销甚至可能不会被注意到。只是简单地将它们声明为原子并不保证线程安全。


没有其他问题。是的,可以在多个线程上访问的任何属性都应该是原子的,否则最终可能会得到意外的结果。