如果不应用某种线程安全,就无法在多个线程上读取和写入属性。现在原则上,对于像字符串这样的简单对象,也许仅仅应用atomic
就足够了。请参阅原子属性和非原子属性之间的区别是什么?更多关于它的作用。
坦白说,我真的很不喜欢atomic
。我知道它的作用,但它似乎是一种获得你真正想要的东西的繁琐方式(而且往往最终比你想要的要少)。这不是一个非常通用的解决方案;我无法atomic
“稍微”自定义访问器(例如添加 asetNeedsDisplay
等)。
这就是为什么我喜欢基于队列的访问器。它们的工作量更大,但它们对很多问题都很有效。
@property (nonatomic, readwrite, strong) dispatch_queue_t thingQueue;
@property (nonatomic, strong) NSObject *thing;
- (id)init {
...
_thingQueue = dispatch_queue_create("...", DISPATCH_QUEUE_CONCURRENT);
...
}
- (NSObject *)thing {
__block NSObject *thing;
dispatch_sync(self.thingQueue, ^{
thing = _thing;
});
return thing;
}
- (void)setThing:(NSObject *)thing {
dispatch_barrier_async(self.thingQueue, ^{
_thing = thing;
});
}
我喜欢这个系统的地方在于,它允许所有读者并行处理。当作者尝试进行更新时,无论涉及多少读者,都可以保证不会饿死。而且它总是很快返回。当值发生变化时,队列中还有一个明确的点,这样在 writer 之前请求 value 的读者总是会得到旧 value,而 writer 之后的读者总是会得到新 value,无论有多少争用在队列中。
关键是getter是同步的,所以会一直等到能拿到值,setter中包含了barrier。屏障意味着“在我运行时,不能从这个队列中安排其他块”。所以你有一堆并行运行的读取器块,然后设置器屏障出现并等待所有读取器完成。然后它单独运行,设置值,然后它后面的读者可以再次并行运行。