Skip to content

Commit

Permalink
Removed semaphore in favour of an atomic property for synchronised ac…
Browse files Browse the repository at this point in the history
…cess.
  • Loading branch information
maratal committed May 13, 2024
1 parent 6541d10 commit 87f5bac
Showing 1 changed file with 12 additions and 22 deletions.
34 changes: 12 additions & 22 deletions Source/ARTGCD.m
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
#import "ARTGCD.h"

@interface ARTScheduledBlockHandle ()

@property (atomic, copy, nullable) dispatch_block_t block;

@end

@implementation ARTScheduledBlockHandle {
dispatch_semaphore_t _semaphore;
dispatch_block_t _block;
dispatch_block_t _scheduledBlock;
}

Expand All @@ -11,44 +15,30 @@ - (instancetype)initWithDelay:(NSTimeInterval)delay queue:(dispatch_queue_t)queu
if (self == nil)
return nil;

// Use a sempaphore to coorindate state. We use a reference here to decouple it when creating a block we'll schedule.
dispatch_semaphore_t semaphore = dispatch_semaphore_create(1);

__weak ARTScheduledBlockHandle *weakSelf = self;
_scheduledBlock = dispatch_block_create(0, ^{
dispatch_block_t copiedBlock = nil;
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
{
// Get a strong reference to self within our semaphore to avoid potential race conditions
ARTScheduledBlockHandle *strongSelf = weakSelf;
if (strongSelf != nil) {
copiedBlock = strongSelf->_block; // copied below
}
ARTScheduledBlockHandle *strongSelf = weakSelf;
if (strongSelf != nil) {
copiedBlock = strongSelf.block; // copied below
}
dispatch_semaphore_signal(semaphore);

// If our block is non-nil, our scheduled block was still valid by the time this was invoked
if (copiedBlock != nil) {
copiedBlock();
}
});

_block = [block copy];
_semaphore = semaphore;
self.block = block; // copied block

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(NSEC_PER_SEC * delay)), queue, _scheduledBlock);

return self;
}

- (void)cancel {
// Cancel within our semaphore for predictable behavior if our block is invoked while we're cancelling
dispatch_semaphore_wait(_semaphore, DISPATCH_TIME_FOREVER);
{
dispatch_block_cancel(_scheduledBlock);
_block = nil;
}
dispatch_semaphore_signal(_semaphore);
self.block = nil;
dispatch_block_cancel(_scheduledBlock);
}

- (void)dealloc {
Expand Down

0 comments on commit 87f5bac

Please sign in to comment.