3

A class of service has a nonatomic property which is set in a serial queue.

@interface Service
@property (strong, nonatomic) NSDictionary *status;
@property (nonatomic) dispatch_queue_t queue;
...
@end

- (void)update:(NSDicationary *)paramDict {
    dispatch_async(self.queue, ^{
        ....
        self.status = updateDict;
    }
}


- (void)someMethod {
    NSDictionary *status = self.status;
}

The app crashed when the getter was invoked, at objc_autorelease + 6, which seems to be a runtime/Clang/llvm invocation.

And the crash log also showed that the status property was just set on the queue thread.

Did it crash because of the lack of atomicity in the accessors? If yes, how and why the getter failed retaining the instance? Did the autorelease pool get drained inside the synthesized nonatomic setter?

Should I implement the getter/setter method, protecting it with queue/a mutex lock?

ZhangChn
  • 3,106
  • 19
  • 40

2 Answers2

1

If you don't mind, change the code like this.

nonatomic -> atomic

Oh Seung Kwon
  • 431
  • 3
  • 11
1

While atomic can address some integrity issues of fundamental data types in multi-threaded code, it's not sufficient to achieve thread-safety in general. Thread-safety is generally achieved through the judicious use of locks or queues. See the Synchronization section of the Threading Programming Guide. Or see Eliminating Lock-Based Code of the Concurrency Programming Guide that describes the use of queues in lieu of synchronization locks.

Assuming your queue is serial, you might be able to make it thread-safe by using the following construct:

- (void)someMethod {
    dispatch_sync(self.queue, ^{

        NSDictionary *status = self.status;

        // do what you need to with status
    });
}

That way, you're effectively using your serial queue to synchronize access to the status dictionary.

By the way, if your queue is a custom concurrent, you might also want to make sure that you replace the dispatch_async in paramDict to be dispatch_barrier_async. If your queue is serial, then dispatch_async is fine.

I'd suggest you try synchronizing your access to status, either using your queue or one of the synchronization techniques described in the Threading Programming Guide.

Rob
  • 371,891
  • 67
  • 713
  • 902
  • I agree that a dispatch queue is generally good in such situation. However, I am not completely sure wether the crash was caused by violation of thread safety or not. – ZhangChn May 20 '13 at 09:23
  • @ZhangChn Oh, yes, I agree. I apologize for neglecting that fairly fundamental point. The source of the exception is not at all clear. I was just reacting to the focus on atomic v nonatomic. Having said that, it's worth making this thread-safe: You have to do that anyway and it may fix the problem. – Rob May 20 '13 at 19:55