using dispatch_sync as a mutex lock
Asked Answered
I

2

6

Here is what I need to do. I hope dispatch_sync would be the best way to do it using GCD

I have a certain piece of critical section code that is placed in the applicationDidBecomeActive callback in Appdelegate..

I am wrapping up that method inside a dispatch_sync call so that it gets 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 the right way for doing it using dispatch_sync?

Impinge answered 1/5, 2013 at 20:40 Comment(4)
Do you want the code to be executed only once on the lifetime of your app?Disconnected
no.. [self runCriticalSection] method would have the necessary logic to do the tasks after a specified timestamp(say 1 day)Impinge
If my runCriticalSection is active then it should not be called again.. I just dont want runCriticalSection to be executing concurrentlyImpinge
Id like to add more.. If the runCriticalSection finishes execution then it can be called againImpinge
D
15

dispatch_sync() does not return until the block has finished, which means that applicationDidBecomeActive does not return until runCriticalSection has finished execution.

This is probably not what you want, therefore you have to use dispatch_async() (as already stated in the other answer).

But you don't want another runCriticalSection to start if the previous one is still running. This can be achieved with a "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);
    });
}
Disconnected answered 1/5, 2013 at 21:18 Comment(1)
never knew we could do a "counting semaphore" with GCD! Nice explanation thanx!Impinge
T
0

The runCriticalSection method will be called multiple times, just not concurrently, so I don't know if this is what you want to achieve.

dispatch_sync just add the specified block to a serial queue (the default priority global queue), so if applicationDidBecomeActive gets fired two times in a row, the queue will contain two blocks that will run runCriticalSection. As the first one starts and finishes its execution, the second one will start, so there will not be any execution of the two blocks at the same time.

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

As an add-on: if runCriticalSection performs an heavy operation, consider that dispatch_sync will block the thread that runs the applicationDidBecomeActive method (the main one if you don't call the method by hand from another thread) until that operation is finished.

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, while dispatch_sync waits for the code inside the block to be completed.

Tertiary answered 1/5, 2013 at 20:54 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.