Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

synchronized blocks and dispatch_async

What happens to the lock in IOS using @synchronized() when we call dispatch_async() within the block.

For ex:

    id myID
-(void) foobar
{
    @synchronized(myID){
        dispatch_async(){ //do stuff with myID};
    }
}

Is the lock still valid within the dispatch_async call? Or more importantly is there any drawbacks in using another @synchronized() call inside dispatch_async()?

like image 767
Alibaba Avatar asked Sep 04 '13 22:09

Alibaba


2 Answers

The lock there would just prevent two different blocks being dispatched at once. However they're dispatched asynchronously, so they may be performed then or may be performed arbitrarily far in the future. The dispatch call also won't wait for them to complete.

So the stuff inside the block isn't synchronised. Options to achieve that with minimal changes are a synchronous dispatch or just @synchronizing within the block.

Depending on what you're doing, the best idea might be to establish a serial dispatch queue and dispatch your blocks onto that.

like image 171
Tommy Avatar answered Sep 24 '22 16:09

Tommy


Assuming you're trying to synchronize the interaction with this myID object in the background queue, you want it the other way around, the lock inside the dispatched block. Right now you have:

@synchronized(myID) {
    dispatch_async(queue, ^{
         // do stuff with myID
    });
}

That's synchronizing the process of adding the dispatched block to your queue, but does not synchronize what you're doing in the background. I suspect that's not what you meant.

You probably intended:

dispatch_async(queue, ^{
    @synchronized(myID) {
         // do stuff with myID
    }
});

It looks very similar, but results in an entirely different behavior. Now, the work dispatched to the background queue is being synchronized.

As a further refinement, if this dispatched block is possibly slow (and I assume it may be), then you'd probably want to constrain the @synchronized block as much as possible:

dispatch_async(queue, ^{

    // do slow stuff in preparation for interacting with `myID`

    @synchronized(myID) {
         // quickly do stuff with myID
    }

    // do anything else here
});

If you do all of the background block within a @synchronized block, you may defeat the entire purpose for dispatching it to the background, namely to minimize impact on the main queue. This last rendition mitigates that problem.

As a final observation, if you have a serial queue (or a non-global concurrent queue in which you do updates with a barrier), that's often used as a technique that eliminates the need for locks altogether, as long as all updates and inquiries for myID are dispatched to that queue. See Eliminating Lock-Based Code in the Concurrency Programming Guide.

like image 24
Rob Avatar answered Sep 22 '22 16:09

Rob