Obj-C 2.0中合成原子属性的锁定细节

10

Obj-C 2.0的属性文档说原子属性在内部使用锁,但它没有记录锁的具体细节。有人知道这是每个属性一个锁,还是与@synchronized(self)使用的隐式锁分开的每个对象一个锁,或者相当于@synchronized(self)?

2个回答

10

观察生成的代码(适用于iOS SDK GCC 4.0 / 4.2 for ARM):

  • 32位的assign属性(包括struct {int32_t v;})直接访问。
  • 大于32位的结构体通过objc_copyStruct()访问。
  • doubleint64_t通过objc_copyStruct()访问,但在GCC 4.0上,它们使用stmia / ldmia直接访问(我不确定在中断的情况下是否保证原子性)。
  • retain / copy访问器调用objc_getProperty()objc_setProperty()

Cocoa with Love:内存和线程安全的自定义属性方法提供了一些有关它们在运行时版本objc4-371.2中如何实现的详细信息。显然,精确的实现可能因运行时而异(例如,在某些平台上,您可以使用原子交换/ CAS来旋转ivar本身而不是使用另一个锁)。


7
使用原子@属性的锁是实现细节--对于适当类型的适当平台,可以进行没有锁的原子操作,如果苹果没有利用它们,我会感到惊讶。无论如何,在任何情况下都无法公开访问锁,因此您无法在同一个锁上@synchronize。几位苹果工程师指出,原子属性并不保证线程安全;原子属性仅保证该值的获取/设置是原子的。为了正确的线程安全,您将需要使用更高级别的锁定或同步,您几乎肯定不希望使用与synthesize getter/setter(s)相同的锁。

好的。我之所以问这个问题,是因为我想知道在同时处理多个属性时,使用原子属性和@synchronized()是否会增加额外的开销。听起来,对于无法使用原子原语完成的操作,将会有额外的开销,因为它实际上使用了两个锁。唉,算了。 - Lily Ballard
在这种情况下,当您已经使用@synchronized或其他受保护的块来实现更高级别的锁定语义时,使用nonatomic属性可能是有意义的。 - Barry Wark
我不希望让代码的所有客户端都必须使用@synchronized块来访问属性,也不想实现自己的getter/setter以便使用@synchronized代替合成的同步操作。 - Lily Ballard
1
如果您正在使用更高级别的同步来排序访问包含这些属性的资源,但允许其他客户端直接访问这些属性,则很难保证依赖于这些更高级别同步来排序事物的多线程代码的正确行为。当然,您的情况可能有所不同,但要小心。那里有危险。 - Barry Wark
我最终甚至没有使用@synchronized,而是使用了一些明确的NSLock对象(用于锁定单个私有实例变量),并依赖于属性访问的顺序。我相信,通过我对属性分配的排序方式,客户端即使从另一个线程访问,也始终可以获得对象的可用视图(例如,如果未标记完成,则可以设置图像,但如果标记为完成,则图像将始终被设置)。 - Lily Ballard

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接