有时我们有一个简单的readOnly属性,其值可能会改变
@property (readonly) NSFetchedResultsController * FetchController;
@property (readonly) NSFetchRequest * FetchRequest;
@property (readonly) NSPredicate * KeywordPredicate;
我想当值改变时,通过某种简单的指针操作眨眼间就完成了。像
这样的东西_FetchRequest = newFetchRequest;
改变的实际过程可能会发生很大变化,但实际变化应该在那一行上。
问题是,这样简单的指针赋值总是原子的吗?如果那一行实际上由几行机器代码组成并且有人要求这些机器代码之间的属性呢?
最后,问题是指针上的简单赋值运算符是否总是原子的。
如果是,那么它是原子的,什么不是?当然,简单赋值运算符对于复杂对象不是原子的。
那么简单的一行赋值运算符到底是什么原子?对于指针和原始类型,它总是会吗?
答案 0 :(得分:5)
我认为你误解了atomic
(或更恰当地,nonatomic
)在这种情况下的含义。最简单的解释可以在objc-accessors.mm
本身找到:
id objc_getProperty_non_gc(id self, SEL _cmd, ptrdiff_t offset, BOOL atomic) {
// Retain release world
id *slot = (id*) ((char*)self + offset);
if (!atomic) return *slot;
// Atomic retain release world
spin_lock_t *slotlock = &PropertyLocks[GOODHASH(slot)];
_spin_lock(slotlock);
id value = objc_retain(*slot);
_spin_unlock(slotlock);
// for performance, we (safely) issue the autorelease OUTSIDE of the spinlock.
return objc_autoreleaseReturnValue(value);
}
如您所见,此处的原子性仅指返回对象的有效性。它保留并自动释放,以保证在您使用它时不会取消分配。
如果未执行此[[obj retain] autorelease]
,则另一个线程可以设置该属性,这将导致先前的属性(即您正在使用的属性)被释放并可能被释放。
答案 1 :(得分:5)
将只读操作视为原子性的,这是一种常见的误解。这不保证。这也是atomicity guarantees thread safety的常见误解,但这是一个不同的主题。
readonly属性上的原子和非原子之间的区别在于atomic
(这是默认值,但未声明)保证从只读检索方法返回的值是整数。
也就是说,如果它是一个对象,它将被保留并自动释放。如果它是一个结构,则将使用适当的锁来确保返回结构的整数值。
请注意,仅仅因为属性是公开读取的,并不排除将其重新声明为readwrite以供内部使用。因此,原子和非原子之间的差异可能非常显着;类可以将readonly属性声明为非原子,同时记录该类上的所有API必须仅从一个线程使用。