Using dispatch_sync as a mutex lock

Here is what I need to do. Hope dispatch_sync will be the best way to do this with GCD

I have a specific code section of a critical section that fits in the applicationDidBecomeActive callback in Appdelegate ..

I end this method inside the dispatch_sync call so that it is called only once no matter how many times applicationDidBecomeActive is called

- (void)applicationDidBecomeActive:(UIApplication *)application{ dispatch_sync(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ NSLog(@"Thread created"); //crtical code [self runCriticalSection]; });} 

Is this done correctly with dispatch_sync?

+4
source share
2 answers

dispatch_sync() not returned until the block finishes, which means applicationDidBecomeActive not returned until completion of the runCriticalSection execution.

This is probably not what you want, so you should use dispatch_async() (as another answer already says).

But you do not want another runCriticalSection start if the previous one still works. This can be achieved using the "counting semaphore", (which are also a feature of GCD):

 static dispatch_semaphore_t sema; // The semaphore static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ // Initialize with count=1 (this is executed only once): sema = dispatch_semaphore_create(1); }); // Try to decrement the semaphore. This succeeds if the count is still 1 // (meaning that runCriticalSection is not executing), and fails if the // current count is 0 (meaning that runCriticalSection is executing): if (dispatch_semaphore_wait(sema, DISPATCH_TIME_NOW) == 0) { // Success, semaphore count is now 0. // Start asynchronous operation. dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ //critical code [self runCriticalSection]; // Increment the semaphore count (from 0 to 1), so that the next call // to applicationDidBecomeActive will start a new operation: dispatch_semaphore_signal(sema); }); } 
+13
source

The runCriticalSection method will be called several times, just not at the same time, so I donโ€™t know, this is what you want to achieve.

dispatch_sync just add the specified block to the serial queue (global default priority queue), so if applicationDidBecomeActive is run twice in a row, the queue will contain two blocks that will run runCriticalSection . When the first one starts and its execution ends, the second one starts, so there will be no simultaneous execution of two blocks.

Is this the expected behavior? If so, dispatch_sync is the way to go.

In addition: if runCriticalSection is performing a heavy operation, consider dispatch_sync to block the thread that starts the applicationDidBecomeActive method (the main one, unless you manually call the method from another thread) until this operation completes.

If you want to avoid this, you should do something like:

 dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ [self runCriticalSectionOnComplete:^{ // If you want to perform something on completion, place it here. This is called asynchronously, without blocking the main thread. }]; }); 

dispatch_async will return as soon as the block is added to the queue, and dispatch_sync will wait for code to complete inside the block.

0
source

All Articles