Let's say I have an NSMutableArray
of objects (NSMutableArray
is not thread-safe), and I have these methods on an object that contains this array (this is a simplified example for the sake of clarity):
- (void)addObject:(id)object {
if (_objectsArray == nil) {
_objectsArray = [NSMutableArray array];
}
[_objectsArray addObject:object];
if (_thread == nil) {
_thread = [[NSThread alloc] initWithTarget:self selector:@selector(__threadEntry:) object:nil];
_thread.name = @"com.company.ThreadName";
[_thread start];
}
}
- (void)removeObject:(id)object {
[_objectsArray removeObject:object];
if (_objectsArray.count == 0) {
_isRunning = NO;
}
}
- (void)stopRendering {
_isRunning = NO;
}
- (void)__threadEntry:(id)sender {
// Set up CADisplayLink on current run loop.
// "_isRunning" is declared as a "volatile BOOL"
_isRunning = YES;
while (_isRendering) {
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
}
// Thread cleanup.
}
- (void)__threadProc {
@autoreleasepool {
[_objectsArray enumerateObjectsUsingBlock:^(id _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
// Do work
}];
}
}
So basically, I have methods that add/remove objects from the mutable array, but work on the objects in the array is performed on a different thread. i.e. addObject
and removeObject
are both only called from the main thread, whereas the work (in __threadProc
) is done on a different thread.
As it is, this code is not thread-safe, as an object can be added/removed while enumeration is under progress in __threadProc
. So what is the correct way to synchronize this?
I'm not sure if locks is the right answer here, because do locks work across different methods? For example, if I put a lock/unlock around [_objectsArray addObject:object]
in the addObject
method and a lock/unlock around the work in __threadProc
, would that work (assuming of course that both are the same lock object (e.g. NSLock
)?
Also, adding/removing objects happens very infrequently compared to how often work is done in __threadProc
.