3

I have an asynchronous method longRunningMethodOnObject:completion:

this method receives an object of type 'Object' - does work with its data and then calls the completion handler.

I need to call many different "longRunningMethods" and wait for all to complete.

I would like all of the "longRunningMethodOnObject" to run asynchronously (parallel) to each other in the "for" loop. (I am not certain if the "longRunningMethodOnObject" runs in serial to each other but this is more of a general question)

I'm not sure I have created a proper semaphore and would appreciate an explanation on the proper way to synchronize between them.

The code for the wrapper function is as follows:

-(void)applyLongRunningOperationOnObjectInArray:(NSArray *)theObjects completion:(completion)block
{
// offsetting to worker thread in my object
  dispatch_async(self.myQueue,^{
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); //Not sure if this should be here or in the for loop
    for(Object *ob in theObjects)
    {
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); // the semaphore for the "for" loop - should this be here? or above the for loop
      [GlobalObject longRunningMethodOnObject:ob completion:^{ // would like each call to be independant of previous call in for loop
        dispatch_semaphore_signal(semaphore); // signaling that it completed
      }];
    }
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); // would like to wait here for each semaphore 
    block(); // invoke the completion handler
  });
}
Avba
  • 14,822
  • 20
  • 92
  • 192
  • possible duplicate of [Opening Several UIDocuments in Succession and Waiting for Them to Finish](http://stackoverflow.com/questions/19383665/opening-several-uidocuments-in-succession-and-waiting-for-them-to-finish) – Jeroen Vannevel Mar 02 '14 at 14:22
  • "When your application no longer needs the semaphore, it should call dispatch_release to release its reference to the semaphore object and ultimately free its memory." - [dispatch_semaphore_create](https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/index.html#//apple_ref/c/func/dispatch_semaphore_create) – jk7 Jan 14 '16 at 17:43

1 Answers1

10

I suppose you could use dispatch_semaphore in this case, but dispatch groups may make the application logic simpler:

NSArray *theObjects = @[@"Apple",@"Orange",@"Peach"];
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t _myQueue = dispatch_queue_create("com.cocoafactory.DispatchGroupExample",
                                                      0);
for( id ob in theObjects ) {
    dispatch_group_async(group, _myQueue, ^{
        //  do some long running task.
    });
}
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

//  now do whatever should be done after
//  all of your objects are processed
//  in your case block()

The Concurrency Programming Guide as a bit on this topic. Scroll down to 'Waiting on Groups of Queued Tasks"

To answer the question about whether tasks are execute concurrently in the queue or not, it depends. In the example above, _myQueue is a serial queue. The global named queues are concurrent. You can also create concurrent queues with the DISPATCH_QUEUE_CONCURRENT queue type as of iOS 5.

FluffulousChimp
  • 9,157
  • 3
  • 35
  • 42
  • dispatch_group_async is definitely a better way to go for this use case. Remember to release the dispatch group when finished with it. dispatch_release(group); – jk7 Jan 14 '16 at 17:47