【问题标题】:thread-safe retain/release线程安全的保留/释放
【发布时间】:2011-06-28 20:13:53
【问题描述】:
我有一个可以从多个后台线程访问的类,可能同时访问。我无法复制该类,因为它的内容重新创建(处理或内存方面)可能很昂贵。
当后台处理仍在继续并访问该属性时,也有可能替换此类的属性。
目前我有定期的保留/释放,但似乎是这种情况(至少在 iOS 4 上)这些不是线程安全的,因为即使它们是完美的配对,它显然会发生 retainCount 随机下降,最终这类被释放。
我正在寻找有关如何使此类线程安全、允许并发访问属性以及允许在属性的“早期版本”仍由其中一个背景保留的情况下修改属性的建议行动。
【问题讨论】:
标签:
iphone
objective-c
ios
【解决方案1】:
保留和释放是原子的。自动释放不是。将保留视为每个线程;如果线程 A 持有一个保留(或保留/自动释放),那么线程 A 的引用将一直有效,直到该保留平衡(或自动释放池耗尽)。
自动释放永远不能用作跨线程所有权转移原语。
除此之外,如果没有更多代码,很难说您的应用出了什么问题。
【解决方案2】:
您是在谈论一个类还是(我想)它的一个实例?
无论如何,根据文档,保留和释放应该是线程安全的。所以你可能在其他地方有一个错误(可能依赖于也可能不依赖于 iOS 4)。
【解决方案3】:
@property 可以声明为'atomic',这是默认的,因此可以安全地从多线程访问,保证结果的一致性:
@property (atomic, ...) NSString *someValue; // atomic is the default, thus optional
保证在getter/setter的整个执行过程中,来自其他线程的代码不会影响结果的一致性。
id val = sharedObject.someValue;
val 中的结果被保留并自动释放,因此无论在其他线程上发生什么,val 将在当前 runloop 周期的剩余时间内(在自动释放池耗尽之前)保持有效。获得val 后,不能保证sharedObject.someValue 会相同,因为另一个线程可以重新分配它。
例如,假设someMethod 在后台线程上定期调用,并且取决于您的sharedObject:
- (void)someMethod {
SomeObject *val = sharedObject.someValue;
// now, val will remain consistent,
// regardless of what happens to sharedObject.someValue
[val doSomething];
if (val.someInt > 50) {
[val doSomethingElse];
}
}
【解决方案4】:
保留/释放应该足以满足您的要求。如果您的对象在两个线程之间被访问,那么他们需要通过一些中间地带进行通信才能访问该对象,并且通常这将是同一个线程。
例子:
//Thread 1 Object
//Setting thread 2's object will occur on the same thread so
//retains and releases will happen in order with no issue
thread2Object.atomicObject = self.atomicObject;
确保您的属性是原子的(线程安全)意味着不要在属性声明中放入非原子的。如果您决定覆盖 getter 或 setter,则需要覆盖两者并使用自己的锁定机制(@synchronize、NSLock 等)。
@propert(retain) NSObject *atomicObject;