6

有时我们有一个简单的 readOnly 属性,它的值可能会改变

@property (readonly) NSFetchedResultsController * FetchController;
@property (readonly) NSFetchRequest * FetchRequest;
@property (readonly) NSPredicate * KeywordPredicate;

我想当值改变时,它是通过某种简单的指针操作在眨眼之间完成的。就像是

_FetchRequest = newFetchRequest;

实际的变化过程可能会发生很大变化,但实际变化应该在这一行上。

问题是,这样简单的指针赋值总是原子的吗?如果这一行实际上由几行机器代码组成,并且有人要求这些机器代码之间的属性怎么办?

最后的问题是指针上的简单赋值运算符是否总是原子的。

如果是这样,什么时候它是原子的,什么不是?简单的赋值运算符对于复杂的对象当然不是原子的。

那么这些简单的单行赋值运算符在多大程度上是原子的呢?对于指针和原始类型,会一直如此吗?

4

2 回答 2

5

将只读操作视为原子性质是一种常见的误解。不能保证。原子性保证线程安全也是一个常见的误解,但这是一个不同的主题。

只读属性上的原子和非原子之间的区别在于atomic(这是默认值,但未声明)保证从只读检索方法返回的值是整数。

也就是说,如果它是一个对象,它将被保留并自动释放。如果它是结构,则将使用适当的锁来确保返回结构的整数值。

请注意,仅仅因为一个属性被公开声明为只读并不排除它被重新声明为内部使用的读写。因此,原子和非原子之间的差异可能非常显着。一个类可能将一个只读属性声明为非原子的,同时还记录了该类上的所有 API 必须仅从一个线程中使用。

于 2012-10-19T07:13:47.697 回答
4

我认为您误解了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]不执行此操作,则另一个线程可以设置该属性,这将导致前一个属性(即您正在使用的属性)被释放并可能被解除分配。

于 2012-10-19T04:39:01.240 回答