2

In my multithreaded application, there is a property that can be accessed concurrently by multiple threads. The property is defined as @property (retain) NSObject *status.

How do I atomically get and retain the property, so I can safely use it in my local scope? What is the best practice to store and retrieve such a value?

NSObject *status = [self status];
[... do some processing on status ...]

// But: I cannot rely on the object assigned to my status variable 
// still being valid, since another thread might have used my 
// [self setStatus] accessor, implicitly calling a release on the old object, 
// releasing it under my feet.
// Not even NSObject *status = [[self status] retain]; would fix that.
justin
  • 104,054
  • 14
  • 179
  • 226
Twilite
  • 873
  • 9
  • 22
  • Why do you think `NSObject *status = [[self status] retain];` will not fix that??? It any wother thread releases your status, by changing property, you will still store reference to it and hold it retained. Just don't forget to balance calling `release`. – Roman Temchenko Jan 31 '12 at 15:17
  • @RomanTemchenko because after `[self status]` has been called but before `retain` there is still a small window of time in which the object could get released. – Twilite Jan 31 '12 at 15:33
  • I am not sure of this. But if you want you can make your own accessor method that will return retained object. `return [_status retain]` – Roman Temchenko Jan 31 '12 at 16:06
  • if you control the code for this "NSObject" then it's your own issue - why can some code modify its internals while other code is releasing it? bad encapsulation – bshirley Jan 31 '12 at 17:32

1 Answers1

4

In my multithreaded application, there is a property that can be accessed concurrently by multiple threads. The property is defined as @property (retain) NSObject *status.

atomic is the default - there is no keyword or specifier required.

How do I atomically get and retain the property, so I can safely use it in my local scope?

Since it's atomic, retained, readwrite and @synthesized, you can just always use the accessors. Provided you access the ivar directly in your initializers and dealloc only -- and use the accessors everywhere else, it will be safe in the regard which you're asking about. The return value is retain+autoreleased. Since it's autoreleased, the object will live on -- at least until the top autorelease pool on the local thread is popped.

The last time I stepped through, it looked something like this (in simple form):

- (NSObject *)object
{
    enter_object_level_spin_lock();
    id ret = [[object retain] autorelease];
    exit_object_level_spin_lock();
    return ret;
}

although i don't remember if the autorelease was in the lock or not (it would ideally be outside for shorter lock times).

What is the best practice to store and retrieve such a value?

Atomic properties do very little for concurrency or thread safety -- don't consider them a substitute for proper thread safety. It's also unusual for thread safety to be covered by what atomic property accessors provide. Typically, you will need more than an atomic for a proper concurrent program. I very very rarely use atomic properties, and make some crazy concurrent programs. If you need high performance/transaction concurrency, you will need to know how to use locks effectively. Of course, there are many ways to avoid concurrent designs as well. My automatic solution involves handling locking myself.

justin
  • 104,054
  • 14
  • 179
  • 226