NSOperation and NSOperationQueue cancellation and ordering questions
NSOperation and NSOperationQueue cancellation and ordering questions
- Subject: NSOperation and NSOperationQueue cancellation and ordering questions
- From: "Karan, Cem (Civ, ARL/CISD)" <email@hidden>
- Date: Fri, 9 Jan 2009 08:36:04 -0500
- Thread-topic: NSOperation and NSOperationQueue cancellation and ordering questions
I am currently using NSOperation (actually, NSInvocationOperation) and NSOperationQueue to decouple my GUI from some long running operations. Some operations are dependent on one another, in a purely linear fashion, so I've been treating them in the same way I'd treat a singly linked list, keeping track of the last operation pushed into the queue. The problem is that the documentation states that we must not modify an operation that is already in the queue; I don't know if calling addDependency is going to do something to an operation in the queue or not. I also don't know if my locking trick for the delegate guaranteed to work or not (I want to make sure that after I check to see that the delegate responds to a particular selector, the delegate isn't changed for another delegate before I have a chance to call the selector). Finally, I'm not sure that my dealloc method is 100% kosher.
Here is some sample code to try to make this more clear (all of this banged out in Outlook, there may be typos). I've inlined questions in the comments in the code:
--- MyOperationInvoker.h ---
@protocol delegateProtocol
@optional // IMPORTANT!
- (oneway void) foo:(int) result; // Single process; do I need oneway?
- (oneway void) bar:(int) result; // Single process; do I need oneway?
@end
@interface MyOperationInvoker : NSObject
{
NSOperationQueue *myQueue;
NSOperation *lastOperation;
id delegate;
NSLock *delegateLock;
}
@property(retain, readwrite) id delegate;
- (void) independentOperation:(id) thing;
- (void) dependentOperation:(id) thing;
@end
--- End of MyOperationInvoker.h ---
--- MyOperationInvoker.m ---
@interface MyOperationInvoker()
@property(retain, readwrite) NSOperationQueue *myQueue;
@property(retain, readwrite) NSOperation *lastOperation;
@property(retain, readwrite) NSLock *delegateLock;
- (void) invokedIndependentOp:(id)thing;
- (void) invokedDependentOp:(id) thing;
@end
@implementation MyOperationInvoker
@synthesize myQueue;
@synthesize lastOperation;
@synthesize delegateLock;
@dynamic delegate;
- (id) delegate
{
return [[delegate retain] autorelease];
}
/*
Note the use of the delegateLock; by using the lock I'm hoping to ensure
that the delegate can't be changed during a critical section within the
invoked*() methods below.
*/
- (void) setDelegate:(id) value
{
if (value != delegate)
{
[self.delegateLock lock];
[value retain];
[delegate release];
delegate = value;
[self.delegateLock unlock];
}
}
- (id) init
{
self = [super init];
if (self != nil)
{
self.delegateLock = [[NSLock alloc] init];
self.delegate = nil;
self.myQueue = [[NSOperationQueue alloc] init];
self.lastOperation = nil;
}
return self;
}
- (void) dealloc
{
self.delegate = nil; // locks the lock while doing this
[self.myQueue cancelAllOperations]; // delegate == nil, therefore no callbacks
// OK, the $64,000 question is, will the dealloc method of NSOperationQueue
// run on the current thread, or will it run on one of the threads that it
// spawned to run the various operations? Basically, are the following 3 calls
// guaranteed to be executed in-order?
self.myQueue = nil;
self.delegateLock = nil;
[super dealloc];
}
- (void) independentOperation:(id) thing
{
NSInvocationOperation *operation =
[[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(invokedIndependentOp:)
object:thing];
[self.myQueue addOperation:operation];
[operation release];
}
/*
Am I able to add the dependencies in the order that I'm doing them in?
Am I allowed to add a dependency when one of the operations is already
in the run queue? What happens if self.lastOperation has already
completed before operation is added to the queue? What happens if
self.lastOperation is cancelled before operation has a chance to run?
Does operation ever run?
*/
- (void) dependentOperation:(id) thing
{
NSInvocationOperation *operation =
[[NSInvocationOperation alloc] initWithTarget:self
selector:@selector(invokedIndependentOp:)
object:thing];
[operation addDependency:self.lastOperation];
[self.myQueue addOperation:operation];
self.lastOperation = operation;
[operation release];
}
/*
Do the locks here prevent the delegate from being changed while I'm
in each critical section? I know that they should, I just want to
double check that my logic is right...
*/
- (void) invokedIndependentOp:(id)thing
{
int result = // Some long running operation
[self.delegateLock lock];
if ([self.delegate respondsToSelector:@selector(foo:)])
{
[self.delegate foo:result];
}
[self.delegateLock unlock];
}
- (void) invokedDependentOp:(id) thing
{
int result = // Some long running operation
[self.delegateLock lock];
if ([self.delegate respondsToSelector:@selector(bar:)])
{
[self.delegate bar:result];
}
[self.delegateLock unlock];
}
@end
--- End of MyOperationInvoker.m ---
Thanks for any pointers,
Cem Karan
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden