I read the Apple documentation on GCD queues and started to wonder what happens if I lets say modify an instance member of type NSMutableArray
which is not thread safe in a serial queue? The serial queue would guarantee me that I execute the operations serially, but I still feel that I need to either do an @syncrhonized
block or other technique to force a memory barrier, since as far as I understand the tasks on my serial queue can be invoked on different threads. Is that correct? Here is a simple example:
@interface Foo : NSObject
-(void)addNumber:(NSNumber*)number;
-(void)printNumbers;
-(void)clearNumbers;
@end
@implementation Foo
{
dispatch_queue_t _queue;
NSMutableArray<NSNumber*>* _numbers;
}
-(instancetype)init
{
if (self = [super init])
{
_queue = dispatch_queue_create(NULL, NULL);
_numbers = [NSMutableArray array];
}
return self;
}
-(void)addNumber:(NSNumber*)number
{
dispatch_async(_queue,
^{
[_numbers addObject:number];
});
}
-(void)printNumbers
{
dispatch_async(_queue,
^{
for (NSNumber* number in _numbers)
{
NSLog(@“%@“, number);
}
});
}
-(void)clearNumbers
{
dispatch_async(_queue,
^{
_numbers = [NSMutableArray array];
});
}
@end;
As far as I understand I could run into memory issues here if I call the member methods from arbitrary threads? Or GCD gives some guarantees under the hood, why I do not need to force memory barriers? Looking at the examples I did not find such constructs anywhere, but coming from C++ it would make sense to touch the member variable under a lock.