Objective-C中的原子属性与线程安全性

时间:2014-01-13 18:19:44

标签: ios objective-c multithreading thread-safety atomicity

在我读过的大多数讨论中,它表明创建属性原子并不能保证它是线程安全的,它只是保证返回的值不会因为一个对象写入它,另一个对象试图同时读它。

我知道这不是线程安全的,因为第三个对象可能正在编写它,而访问它的对象不会被垃圾回收,它不完全确定它会获得哪个值当多个对象同时写入它时,它可能会获得它们的任何值。

因此,当我们说它不会返回垃圾时,垃圾是否意味着如果一个对象是非原子的并且一个对象试图访问它而另一个正在写入它,它可能会得到结果中期写入,只能得到写入带来的部分,不完整版本的变化?这是什么"垃圾"从这个意义上讲,是什么原子属性有助于防止?

5 个答案:

答案 0 :(得分:37)

Objective C中的atomic属性可确保您永远不会看到部分写入。 如果@property具有属性atomic,则无法仅部分写入该值。二传手就是这样:

- (void)setProp:(NSString *)newValue {
    [_prop lock];
    _prop = newValue;
    [_prop unlock];
}

因此,如果两个线程想要同时写入值@“test”和@“otherTest”,那么 在任何给定时间,财产只能是财产的初始值或@“test”或@“otherTest”。 nonatomic更快,但值是垃圾值,并且没有@“test”/ @“otherTest”(thx @Gavin)或任何其他垃圾值的部分字符串。

但是 atomic只是线程安全且使用简单。 它没有被保证。 Appledoc说以下内容:

  

考虑XYZPerson对象,其中一个人的第一个和最后一个   使用来自一个线程的原子访问器更改名称。如果另一个   线程同时访问两个名称,原子getter方法   将返回完整的字符串(没有崩溃),但没有   保证这些值相对于每个值都是正确的名称   其他。如果在更改之前访问了第一个名称,则是最后一个名称   更改后访问名称,最终会出现不一致的情况,   不匹配的一对名字。

我根本没遇到使用原子的问题。我设计了代码,原子属性没有问题。

答案 1 :(得分:5)

回答你的第三段;基本上是的。线程正在写入数字时无法读取原子序数。

例如,如果一个线程写入了原子四字节数的前两个字节,并且在另一个线程上请求读取该数字,则该读取必须等到所有四个字节都被写入。

相反,如果一个线程已写入非原子四字节数的前两个字节,并且此时在另一个线程上请求读取该数字,它将读取前两个新数据字节,但是从其他两个字节中的先前写操作中获取旧数据。

答案 2 :(得分:3)

罗伯特哈维的回答是正确的,但有一个子案例需要考虑人们经常会错过。请考虑以下代码:http://pastebin.com/S7XyJm6G

除了阻止您读取部分写入的值之外,原子属性还会阻止您获取不能控制其生命周期的对象(它们通过保留然后自动释放对象来执行此操作)。这在单线程代码中非常重要,例如我链接的示例,但在多线程代码中更为重要,其中另一个线程可能导致对象从您下面释放出来。

答案 3 :(得分:0)

在并发编程中:

atomic表示在某个线程(线程#1)和其他线程(线程#2)中为写入操作访问的属性值是否尝试访问原子值以进行读取或写入操作,然后是其他线程(线程#2)等待线程#1完成其任务。 换句话说,原子以先到先得的方式同步财产的访问。

非原子意味着如果在某个线程(线程#1)和其他线程(线程#2)中为写入操作而访问的属性值尝试访问非原子值以进行读取或写入操作,那么其他线程(线程#) 2)获得值立即获得旧值

答案 4 :(得分:0)

明确实施

  

@property(atomic,retain)NSNumber * count

就像这样

- (NSNumber *)count {
    NSNumber *count;
    @synchronized(self) {
        count = [_count retain]; // +1
    }
    return [count autorelease]; // delayed -1
}

- (void)setCount:(NSNumber *)count {
    id oldValue;
    @synchronized(self) {
        oldValue = _count;
        _count = [count retain];
    }
    [oldValue release];
}

Atomic是属性的默认行为。原子属性在获取或设置值时会增加一定程度的线程安全性。也就是说,无论其他线程正在做什么,该属性的getter和setter将始终完全完成。这些属性的访问速度比非原子等效的要慢一些。

显然我们会实施

  

@property(nonatomic,retain)NSNumber * count

像这样

- (NSNumber *)count {
    return _count;
}

- (void)setCount:(NSNumber *)count {
    if (count != _count) {
        id oldValue = _count;
        _count = [count retain];
        [_oldValue release];
    }
}

非原子属性不是线程安全的,并将直接返回其属性。这将比原子属性更快,但如果不采取预防措施,显然会带来一些风险。

setter&这些非原子属性的吸气剂