Objective c 为什么原子在复杂对象的线程安全性方面不够
Objective c 为什么原子在复杂对象的线程安全性方面不够,objective-c,Objective C,atomic关键字应用于类的属性,以确保线程安全 对于基本数据类型,atomic的使用是线程安全的,但对于复杂对象(模态对象)则不安全。为什么? 提前感谢您的友好回复 更新 如果Person是一个具有属性name,age,address的类 考虑 @property(原子,强)Person*adam 对象的线程安全距离有多远?即使在编辑之前,这实际上也是一个重复,尽管它并不明显 因为这个答案经常被提及,所以我添加了以下内容来强调线程安全实际上就是拥有某种事务模型,在这种模型中,读和写是受控的,当
atomic
关键字应用于类的属性,以确保线程安全
对于基本数据类型,atomic
的使用是线程安全的,但对于复杂对象(模态对象)则不安全。为什么?
提前感谢您的友好回复
更新
如果Person
是一个具有属性name
,age
,address
的类
考虑
@property(原子,强)Person*adam代码>
对象的线程安全距离有多远?即使在编辑之前,这实际上也是一个重复,尽管它并不明显
因为这个答案经常被提及,所以我添加了以下内容来强调线程安全实际上就是拥有某种事务模型,在这种模型中,读和写是受控的,当读或写发生时,系统处于一种已知的、完整的状态
当多个依赖属性处于活动状态时,单个属性的原子性也不能保证线程安全
考虑:
@property(atomic, copy) NSString *firstName;
@property(atomic, copy) NSString *lastName;
@property(readonly, atomic, copy) NSString *fullName;
在这种情况下,线程A可以通过调用setFirstName:
然后调用setLastName:
来重命名对象。同时,线程B可以在线程A的两次调用之间调用fullName
,并将接收新的名字和旧的姓氏
为了解决这个问题,您需要一个事务模型。也就是说,一些其他类型的同步和/或排除,允许在更新依赖属性时排除对全名的访问。不同之处在于,对象具有自己的方法和行为,这可能导致对象在其setter和getter之外发生更改
Atomic关键字仅在编译器合成的setter和getter之间提供线程同步
这通常足以为原语属性提供线程安全性,因为其底层ivar只能通过其setter和getter访问
但是,对于对象属性,这只会为指向该对象的指针提供线程安全性。setter和getter本身是同步的,但是该对象的某些其他方法可能会从不同的线程修改它,并且该属性总体上不会是线程安全的。如果你想让它安全,你必须实现与所有可能修改对象的方法同步
例如,以下不可变字符串应该是线程安全的,因为它只能通过访问器进行修改
@property (atomic, strong) NSString * immutableString;
而下面的可变线程将不是线程安全的
@property (atomic, strong) NSMutabeString * mutableString;
我不认为这是上述相关问题的完全重复。我怀疑,对于复杂对象来说,原子可能不安全的一个原因是,该对象有自己的非原子属性。无论哪种方式,我都希望看到这个问题的明确答案(因为我在最近的一次求职面试中被激怒了,当时我无法很快或权威性地回答这些问题)。你说的“复杂对象”是什么意思?所有属性都存储“基本数据”类型。请记住,引用是存储的,而不是对象。@MichaelDautermann不是完全重复的,但现在我添加了一个显式示例。这里的讨论是关于为什么原子并不意味着线程安全也适用于复杂对象。基本上,当您有多个必须同步维护的属性时,单个属性的原子性不足以实现线程安全。