I want to issue a notification when all 4 different threads have finished their work. I’m keeping count of the total threads and have a listener that does some work when the threads have finished.
Is the following a safe way to do this?
// ivars:
NSMutableArray *list;
OSSpinLock lock;
#define MAX_ALLOWED 4
- (void)someThreadedWork
{
// Iterate thru 4 different items using gcd and update
for (int x = 0; x < MAX_ALLOWED; ++x)
{
dispatch_async(some_queue, ^{
// Do some work.. once done,
[self updateCount:ix];
});
}
}
- (void)updateCount:(NSInteger)newCount
OSSpinLockLock(&lock);
{
[list addObject:[NSNumber numberWithInt:newCount]];
if ([list count] == MAX_ALLOWED)
{
_allValuesUpdatedAt = [NSDate date];
}
}
OSSpinLockUnlock(&lock);
}
- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object
change:(NSDictionary*)change context:(void*)context
{
// When I get the 'allItemsUpdatedAt' event, I will perform some other work
}
- (id)init {
if (self = [super init])
{
// there is a corresponding removeObserver in the dealloc
list = [[NSMutableArray alloc] init];
[anInstance addObserver:self
forKeyPath:@"allItemsUpdatedAt"
options:NSKeyValueObservingOptionNew
context:NULL];
}
return self;
}
HachiEthan’s comment about dispatch_async is exactly correct. If you use dispatch_group_async instead, then you don’t need any locking at all, nor do you have to keep track of the threads that are currently working. It’ll do all of this for you.
See “Waiting on Groups of Queued Tasks” in the Concurrency Programming Guide for a faster, simpler, more robust, and less energy intensive approach to this problem. See also “Migrating Away from Threads” in the same document to learn how to convert thread-based systems to queue-based systems.