does the following code has some issue when timeout (no ARC case)?
how about the dispatch_semaphore_signal is called after dispatch_release(semaphore)? I know a dispatch object is asynchronously deallocated once all references to it are released (the reference count becomes zero), so the reference of the semaphore is not 0 in the following code?
is it necessary to add __block for semaphore?
dispatch_time_t timeout = DISPATCH_TIME_FOREVER;
if (waitTime > 0)
{
timeout = dispatch_time(DISPATCH_TIME_NOW, waitTime * NSEC_PER_SEC);
}
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
dispatch_barrier_async(_dispatchQueue, ^{
dispatch_semaphore_signal(semaphore);
});
dispatch_semaphore_wait(semaphore, timeout);
dispatch_release(semaphore);
thanks a lot!
Based on comments.
I think you need something like this. The done
variable needs to be synced / atomic and there are two places in the code that need to be synced on some common lock. In fact, since you only access done
inside those pieces it does not need to be synced.
done = NO
dispatch_barrier ...
stuff
sync {
if(!done)
signal
done = YES;
}
wait with timeout
cancel block
sync {
if( ! done )
signal
done = YES
}
// You can even test the logic as below
if DEBUG
{
assert done == YES
}
release
I am not sure what the impact of cancel block will be in non ARC environment but think it will be fine.
This will balance the signals and waits and will cause the release to work and also prevent you from signalling the released semaphore.
Here is an outline implementation in Objective-C
__block BOOL done = NO;
NSObject * lock = NSObject.new;
dispatch_semaphore_t s = dispatch_semaphore_create ( 0 );
dispatch_queue_t queue = dispatch_queue_create( "bak",
dispatch_queue_attr_make_with_qos_class( DISPATCH_QUEUE_CONCURRENT,
QOS_CLASS_DEFAULT,
DISPATCH_QUEUE_PRIORITY_DEFAULT ) );
dispatch_block_t block = dispatch_block_create ( DISPATCH_BLOCK_BARRIER, ^ {
// Change this time to determine which one fires first
[NSThread sleepForTimeInterval:1];
@synchronized ( lock ) {
if ( ! done )
{
done = YES;
dispatch_semaphore_signal ( s );
NSLog ( @"Inside fired" );
}
}
} );
// Start the block
dispatch_async ( queue, block );
// ... or change time here to determine which one fires first
dispatch_semaphore_wait ( s, dispatch_time ( DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC ) );
@synchronized ( lock ) {
if ( ! done )
{
done = YES;
dispatch_semaphore_signal ( s );
NSLog ( @"Outside fired" );
}
}
// Done, release stuff *only* if not ARC
dispatch_release ( s );
dispatch_release ( queue );
dispatch_release ( block );
lock.release;