Reputation: 3668
In my app I am running a server in the background. I am using a NSOperation
to do so. (I used GCD before but I need to be able to stop it, so I switched to NSOperation
, but I still cannot figure out how.)
So essentially, my NSOperation
subclass looks like this:
- (void)main {
server_main(var1, var2);
}
Since this is a server, the server_main
function basically does not return. I also have no control to the implementation of that function.
Occasionally, the user changes the settings of the server. When this occurs, I would like to stop and then restart the server. If I understand correctly, I need to do something like if (self.isCancelled)
in the NSOperation
subclass, but since it will be stuck in the server_main
function, I doubt it will actually work.
So how can I stop the server?
Many thanks!
Upvotes: 0
Views: 896
Reputation: 437452
To do it properly see Responding to Cancellation Events in the Concurrency Programming Guide, which says:
Although the
NSOperation
class provides a way for clients to cancel an operation, recognizing the cancellation event is voluntary by necessity. If an operation were terminated outright, there might not be a way to reclaim resources that had been allocated. As a result, operation objects are expected to check for cancellation events and to exit gracefully when they occur in the middle of the operation.To support cancellation in an operation object, all you have to do is call the object’s
isCancelled
method periodically from your custom code and return immediately if it ever returnsYES
.
This is a long winded way of saying that I really think you need to be able to change server_main
so that it either:
Check isCancelled
periodically, or
Have it provide a callback/progress delegate method block so you can do that yourself as well as some additional function/method you can call to cancel server_main
, letting it to the critical clean-up process.
If you just start killing processes (if you even can), you will undoubtedly leak resources or leave that server_main
in an inconsistent state.
I know this isn't the answer you're looking for, but it's the way canceling of operations work. Sorry.
Upvotes: 2
Reputation: 9913
you can use the
- (void)setSuspended:(BOOL)suspend
method on NSOperationQueue? And before adding a new operation, check if the queue is suspended with isSuspended?
Edit : Here parameter suspend If YES, the queue stops scheduling queued operations for execution. If NO, the queue begins scheduling operations again. Discussion This method suspends or resumes the execution of operations. Suspending a queue prevents that queue from starting additional operations. In other words, operations that are in the queue (or added to the queue later) and are not yet executing are prevented from starting until the queue is resumed. Suspending a queue does not stop operations that are already running.
Operations are removed from the queue only when they finish executing. However, in order to finish executing, an operation must first be started. Because a suspended queue does not start any new operations, it does not remove any operations (including cancelled operations) that are currently queued and not executing.
Hope it helps you.
Upvotes: 0
Reputation:
You can try this code:
@interface Canceller
{
BOOL _shouldCancel;
}
- (void)setShouldCancel:(BOOL)shouldCancel;
- (BOOL)shouldCancel;
@end
@implementation Canceller
- (void)setShouldCancel:(BOOL)shouldCancel {
_shouldCancel = shouldCancel;
}
- (BOOL)shouldCancel {
return _shouldCancel;
}
@end
static void test(int a){
static Canceller * canceller = nil;
if(q){
[canceller setShouldCancel:YES];
[canceller release];
dispatch_suspend(q);
dispatch_release(q);
q=nil;
}
canceller = [[Canceller alloc] init];
q=dispatch_get_global_queue(0,0);
dispatch_async(q,^ {
while(![canceller shouldCancel]){NSLog(@"query %d",a);sleep(2);}
});
}
Hope it helps.
Upvotes: 0