0

I need to protect some code to invalidate a serial queue, in an -invalidate method, so that these codes would be run once, like the dispatch_once in the singleton paradigm.

My intuition is:

@property(nonatomic, readonly, getter=isValid) BOOL valid;
@property(nonatomic) dispatch_queue_t serialQueue;
...
- (void)invalidate {
    if ([self isValid]){
        dispatch_sync(self.serialQueue, ^{
            if ([self isValid]) {
                _valid = NO;
                // relinquish resources here
            }
        });
        if (self.serialQueue) {
            dispatch_release (self.serialQueue);
        }
    }
}

This -invalidate method would be called either explicitly or by -dealloc. And I want to make sure that the resources would be relinquished once and only once.

Is this implementation thread-safe?

Is it a better way to implement a dispatch_once block in a per-instance manner?

@property(nonatomic, readonly) dispatch_once_t invalidated;
...
- (void)invalidate {
    dispatch_once(&_invalidated, ^{
        dispatch_sync(logQueue, ^{
            // double check
            if (self.isValid) {
                self.valid = NO;
                // relinquish things
            }
        }
    }
}
Ria
  • 10,237
  • 3
  • 33
  • 60
ZhangChn
  • 3,154
  • 21
  • 41
  • dealloc already handles this for you. – deleted_user Sep 24 '12 at 08:30
  • I cannot rely on `dealloc` because it is not guaranteed what time it is actually called. I need to release some resources, e.g. a file handle, before removing the file from disk. These should be done like a transaction. And I'd rather invalidate the instance which held the resource than release the instance itself. – ZhangChn Sep 24 '12 at 08:48
  • If you have multiple instances managing the same resource you have bigger problems than dispatch_once. – deleted_user Sep 24 '12 at 08:50
  • @stackmonster: "dealloc already handles this for you" - Only on iOS 6/OS X 10.8 or later, see the answer to this question: http://stackoverflow.com/questions/8618632/does-arc-support-dispatch-queues. Also I assumed from the question that there are other resources to release, but I may of course be wrong. – Martin R Sep 24 '12 at 08:51
  • I may have multiple(, typically 2) instances referring to the same instance that manages the resource, hence I want to keep it thread-safe by enforcing a serial dispatch queue. – ZhangChn Sep 24 '12 at 08:53
  • 1
    most of these discussions just muddy the waters. If you attempt to manage a single resource with multiple instances and need a moment certain deallocation of resources you are reimplementing garbage collection. Alloc and dealloc properly, encapsulate resources properly and you wont have these problems. – deleted_user Sep 24 '12 at 08:53
  • Maybe I should revise the design like using weak reference than strong ones to decouple multiple-to-one ownerships. – ZhangChn Sep 24 '12 at 09:13

1 Answers1

1

If invalidate does not need to be thread-safe, you can just do

- (void)invalidate {
    if ([self isValid]) {
        _valid = NO;
        // relinquish resources here
    }
}

because setting _valid = NO already guarantees that the function is called only once.

Things get a little more complicated if the invalidation must be done in a thread-safe manner. You could use dispatch_once. The disadvantage is that this really works only once. So if you validate your object again later, invalidation will not work anymore.

Alternatively, you can use one of the Synchronization methods, e.g. @synchronized:

- (void)invalidate {
    @synchronized(self) {
        if ([self isValid]) {
            _valid = NO;
            // relinquish resources here
        }
    }
}
Martin R
  • 529,903
  • 94
  • 1,240
  • 1,382
  • Is the use of `@synchronized(){}` still recommended? – ZhangChn Sep 24 '12 at 08:45
  • @ZhangChn: It is one of the synchronization methods in Apple's "Threading Programming Guide". If you have information that it is no longer recommended, I would be interested in a reference. – Martin R Sep 24 '12 at 08:48