I have a class that is accessed from multiple background threads, potentially at the same time. I cannot copy the class because it's contents is potentially expensive to recreate (processing or memory-wise).
It is also possible that a property of this class is replaced while processing in the background is still going on and accessing this property.
At present I have regular retain/releases but it seems to be the case (at least on iOS 4) that these are not thread-safe be开发者_StackOverflow社区cause even though they are perfectly pairs it apparently occurs that the retainCount drops randomly and eventually this class gets deallocated.
I'm looking for suggestions on how to make this class thread-safe, permit concurrent access of properties and permit for a property to be modified while an "earlier version" of the property is still held onto by one of the background actions.
Retain and release are atomic. Autorelease is not. Think of retains as per-thread; if thread A is holding a retain (or a retain/autorelease), then thread A's reference will be valid until that retain is balanced (or the autorelease pool is drained).
Autorelease can never be used as a cross-thread ownership transfer primitive.
Beyond that, hard to say what is going wrong in your app without more code.
Are you talking about a class or (I suppose) an instance of it?
Anyway, retain and release should be thread-safe according to the docs. So you probably have a bug somewhere else (which might or might not be dependent on iOS 4).
A @property can be declared 'atomic', which is the default, so it can be accessed safely from multi-thread, guaranteeing the consistency of the result:
@property (atomic, ...) NSString *someValue; // atomic is the default, thus optional
It guarantees that throughout the execution of the getter / setter, code from another thread won't affect the consistency of the result.
id val = sharedObject.someValue;
The result in val
is retained and autoreleased, so no matter what happens on other threads, val
will stay valid for the remainder of the current runloop cycle (before the autorelease pool is drained). After getting val
, there is no guarantee that sharedObject.someValue
will be the same, as another thread could reassign it.
Example, assuming someMethod
is called periodically on a background thread and depends on your 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];
}
}
Retain/Release should sufficient for what you are trying to do. If your object is accessed between two threads there is some middle ground they need to communicate through to access this object and usually that will be the same thread.
Example:
//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;
Making sure that your properties are atomic (thread safe) means just not putting nonatomic in the property declaration. If you decide to override a getter or a setter you need to override both and use your own locking mechanism (@synchronize,NSLock,etc..).
@propert(retain) NSObject *atomicObject;
精彩评论