Martin Perry
Martin Perry

Reputation: 9527

GCD - dispatch_barrier_async - waiting till done

I am having this code

-(void) Method {

    // WAIT_CODE

    dispatch_async(myQueue,^{ CODE 1});
    dispatch_async(myQueue,^{ CODE 2});  
    dispatch_barrier_async(myQueue,^{
        // SOME CODE
        dispatch_async(dispatch_get_main_queue(), ^{GUI UPDATE }
    });
}

Problem is, when I call this method again and SOME CODE was not executed yet, I need to wait on WAIT_CODE before continue (BUT GUI must stay active)... How can I do this ?

Upvotes: 2

Views: 1993

Answers (3)

Andrew
Andrew

Reputation: 7720

Option 1) Does it make sense to add a second serial queue so the code inside -method is run only when no other calls to the method are executing?

For example, in the caller would you have:

mySerialQueue = dispatch_queue_create("com.myapp.my-serial-queue", DISPATCH_QUEUE_SERIAL);
dispatch_async(mySerialQueue, [self method]);

Option 2) Make myQueue serial instead of concurrent (I assume it is concurrent because dispatch_barrier_async() only works on concurrent queues you own).

myQueue = dispatch_queue_create("com.myapp.myqueue", DISPATCH_QUEUE_SERIAL);    
dispatch_async(myQueue,^{ CODE 1});
dispatch_async(myQueue,^{ CODE 2});  
dispatch_async(myQueue,^{
   SOME CODE
   dispatch_async(myQueue,^{
      WAIT_CODE
      dispatch_async(dispatch_get_main_queue(), ^{GUI UPDATE }
   });
});

Option 3) Reorder the code to add WAIT_CODE after SOME_CODE

dispatch_async(myQueue,^{ CODE 1});
dispatch_async(myQueue,^{ CODE 2});  
dispatch_barrier_async(myQueue,^{
    SOME CODE  // this code must block
    WAIT_CODE  // this code must block
    dispatch_async(dispatch_get_main_queue(), ^{ GUI UPDATE }
});

Upvotes: 1

aLevelOfIndirection
aLevelOfIndirection

Reputation: 3522

You could also synchronize using a semaphore. Here is how your code could be structured.

-(void) Method 
{

  // Declared dispatch_semaphore_t _synch;
  // in init: _synch = dispatch_semaphore_create(1);
  // in dealloc: dispatch_release(_synch);
  //
  // Initialized with 1 so first call goes through.
  // Subsequent calls are serialized and must wait on a signal.
  //
  dispatch_time_t blockingSleepSecondsIfNotDone = 0.01;
  while (!dispatch_semaphore_wait(wait, DISPATCH_TIME_NOW))
      usleep(USEC_PER_SEC * blockingSleepSecondsIfNotDone);

  WAIT_CODE

  dispatch_async(myQueue,^{ CODE 1});
  dispatch_async(myQueue,^{ CODE 2});  
  dispatch_barrier_async(myQueue,^{
    SOME CODE
    dispatch_semaphore_signal(_synch);
    dispatch_async(dispatch_get_main_queue(), ^{GUI UPDATE }
  });
}

Upvotes: 1

Jody Hagins
Jody Hagins

Reputation: 28409

What are you trying to do?

Why do you have to wait?

If the queue is still executing SOME CODE when you call this function again, those "new" blocks will get enqueued, and will not execute until after the SOME CODE block runs. I assume myQueue is a concurrent queue. The barrier call will wait for all previously enqueued blocks to execute before it runs. Furthermore, it will be the only block that runs on the queue, until it is done, then the queue will resume executing blocks concurrently.

Upvotes: 1

Related Questions