我知道有关于原子与非原子答案的答案,但它们似乎都相当陈旧(2011年及之前),因此我希望获得更新的建议。我的理解是非原子属性更快但不是线程安全的。这是否意味着可能同时从多个线程访问的任何属性应始终是原子的?是否存在可以使其成为非原子的条件?在确定是否将属性设为原子或非原子时还有哪些其他问题?
答案 0 :(得分:5)
声明属性atomic
会使编译器生成其他代码,以防止对属性进行并发访问。此附加代码锁定信号量,然后获取或设置属性,然后解锁信号量。与设置或获取原始值或指针相比,锁定和解锁信号量非常昂贵(虽然如果考虑应用程序的总体流量,通常可以忽略不计)。
由于iOS下的大多数课程,尤其是与UI相关的课程,都将在单线程环境中使用,因此可以安全地删除atomic
( ie写nonatomic
,因为属性默认为atomic
),即使操作相对便宜,也不想为不需要的东西付费。
答案 1 :(得分:1)
将属性声明为原子并不一定使其成为线程安全的。
Atomic是默认设置,与非原子设备相比需要一些额外的开销。如果线程A在该属性的getter中途,并且线程B更改了setter中的值,则使用atomic将确保从getter返回可行的整个值。如果你使用nonatomic没有这样的保证,就不会生成额外的代码,因此非原子性更快。
然而,这并不保证线程安全。如果线程A调用getter并且线程B和C正在使用不同的值更新线程,则线程A可以获得任一值,并且无法保证它将获得哪一个。
要专门回答您的问题,许多情况允许非原子属性,如果不是大多数。虽然使用原子的额外开销可能是可以忽略不计的。简单地说,您的属性是在不同的线程上读取还是设置?如果没有,你很可能不需要将它们声明为原子,但额外的开销可能甚至不明显。只是简单地将它们声明为原子并不能保证线程安全。
答案 2 :(得分:1)
在大多数情况下,在多线程环境中属性是否为原子属性并不重要。
什么?
在大多数情况下,在多线程环境中属性是否为原子属性并不重要。
这样做的原因是使一个属性"线程安全"通过打开原子性,不使您的代码线程安全。要实现这一点,您需要更多工作,这项工作通常会隐式确保不会并行访问该属性。
我们举个例子:您有一个Person
类,firstName
和lastName
都属于NSString*
。您只想添加用空格分隔的两个名称以具有全名。
NSString *fullName = [NSString stringWithFormat:@"%@ %@", person.firstName, person.lastName];
您知道其他线程可以在您执行此操作时更新属性。使属性原子化并没有任何帮助。如果在读取第一个名称之后但在读取第二个名称之前更改了人员的姓氏,这没有任何帮助。如果在计算全名后更改了人员姓名,这没有用,因为这可能在下一刻无效。
您必须序列化操作,而不是属性访问。但原子性只序列化访问。因此,如果至少一个操作具有多个访问权限,则无效。所有案件中99,999999373%。
忘记属性原子性。这没有意义。
答案 3 :(得分:-1)
没有其他问题。是的,任何可以在多个线程上访问的属性都应该是原子的,否则最终会产生意外结果。