I would like to grab justin's option "dispatch APIs" for a short example:
Concurrent access to shared resources can be made safe through executing all accesses on a dedicated serial queue, lets call it "sync_queue".
This "sync_queue" will likely be a private queue of the class whose ivars is the resource you want to modify.
You may now define a read/write nonatomic property, for example:
@propery (nonatomic) NSArray* array;
The write access can be implemented as shown below:
- (void) setArray:(NSArray* newValue)
{
dispatch_async(sync_queue, ^{
_array = newValue;
});
}
Note that a write access is asynchronous.
The read access to the property will be implemented as follows:
- (NSArray*) array:(NSArray* value)
{
if (dispatch_get_specific(SyncQueueID) == sync_queue_id)) {
return _array;
}
else {
__block NSArray* result = nil;
dispatch_sync(_sync_queue, ^{
result = _array;
});
return result;
}
}
Unlike a write access, a read access requires to be synchronous. The method also has to check if the current execution context is not already the sync_queue or a child or any grand children of the sync queue - otherwise, the read access would cause a dead lock.
To identify the current execution context we associate a particular identifier with the sync queue, using function dispatch_queue_set_specific() when creating it. Later we use dispatch_get_specific to obtain this identifier from the current queue or from the parent or any grand parent queue. If it returns this particular identifier, the method is executing on the sync queue respectively on a child queue or any grand children. If that's true, the method returns the value immediately. Otherwise, it synchronously schedules on the sync queue.
Note:
If the shared resource will be accessed by UIKit, the sync_queue shall be the main queue.