Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSMutableArray collection and @Synchronized blocks

In Objective C I'm using a NSMutableArray instance from various thread and I'm using @synchronized to make it thread safe. currently all my acces to this array are protected with a @synchronized block, even objectAtIndex: method. Nevertheless I wonder which methods call really need to be protected with @synchronized. do I need to protect read access ?

What would happens if 'ObjectAtIndex' is not protected and called at the same time that 'removeObject' ?

If all methods are protected by a @synchronized what about performance? (I'writing a tcp/udp game server and really don't want to overprotect these array if it would decrease perf or generate locks).

for example I suppose that the 'containsObject:' method will enumerate to find the object and that I should avoid a concurent call to 'removeObject:' in another thread.

Perhaps a good solution would be to have too different locks (for read and write access)...

Help and suggestion are welcome !

Thanks a lot.

Please find a sample code below to illustrate :

@interface TestClass : NSObject
{
    NSMutableArray * array;
}

@end

@implementation TestClass

- (id)init
{
    self = [super init];
    if (self)
    {
        array = [NSMutableArray array];
    }
    return self;
}

-(id)objectAtIndex:(NSUInteger)index
{
    @synchronized(array) **// IS IT USEFUL OR NOT ??**
    {
        return [array objectAtIndex:index];
    }
}

-(void)removeObject:(id)object
{
    @synchronized(array)
    {
        [array removeObject:object];
    }
}

-(void)compute
{
    @synchronized(array)
    {
        for (id object in array)
        {
            [object compute];
        }
    }
}

@end
like image 677
Clement M Avatar asked Jun 13 '13 15:06

Clement M


1 Answers

Yes, you have to synchronize read accesses to prevent them from happening simultaneously with mutations. Read accesses can safely run simultaneously with other read accesses, though.

If you have multiple readers, then it's worth investigating a read-write locking scheme. You can use pthread read-write locks (i.e. pthread_rwlock_...()).

Alternatively, you can use GCD on OS X 10.7+ and iOS 5+ with the "barrier" routines. Create a private concurrent queue. Submit all read operations to it in the normal fashion (e.g. dispatch_sync()). Submit mutation operations to it using a barrier routine such as dispatch_barrier_async(). (It can be asynchronous because you generally don't need to know that the mutation has completed before continuing. You only need to know that all reads submitted after you submit the mutation will see the results of the mutation, and the barrier guarantees that.)

You can learn more about this if you have access to the WWDC 2011 session video for Session 210 - Mastering Grand Central Dispatch.

like image 120
Ken Thomases Avatar answered Sep 28 '22 18:09

Ken Thomases