Reputation: 29316
In my main function for my command line program, I create a new instance of an NSThread
subclass, and call start
on it, where it runs a timer in a different thread. If the user wants to stop the timer, they type "stop" and I want it to end the thread as well.
How would I go about doing this? I'm gathering that I should call cancel
on the thread, then in the main
of the NSThread
subclass check if isCancelled
is YES
, but as far as I know main is only called when I call start
initially. I don't see where else I could check isCancelled
in order to call [NSThread exit]
.
How should I handle exiting this NSThread?
Upvotes: 1
Views: 622
Reputation: 8608
You check for isCancelled
in your NSThread
subclass. You check for isCancelled
throughout your code in NSThread
subclass. When you call cancel
, your NSThread
subclass continues to run until it hits a check for isCancelled
. What you do is place the isCancelled
check multiple places in hopes when you call cancel
it hits a isCancelled
check and exits as soon as possible.
From your example code you posted I changed the TimerThread.m
to look like this and it works fine:
#import "TimerThread.h"
#import "Giraffe.h"
@interface TimerThread () {
Giraffe *giraffe;
}
@end
@implementation TimerThread
- (void)main {
if (self.isCancelled)
return;
giraffe = [[Giraffe alloc] init];
[NSTimer scheduledTimerWithTimeInterval:0.5 target:self selector:@selector(calculate:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] run];
}
- (void)calculate:(NSTimer*)timer {
if (self.isCancelled) {
[timer invalidate];
return;
}
[giraffe calculateValues:timer];
}
@end
Upvotes: 3
Reputation: 19098
Based on the various comments, you likely want a main method as follows:
+ (void) threadMain
{
@autoreleasepool {
[[NSThread currentThread] setName:@"WorkerThread.sharedThread"];
NSRunLoop* runLoop = [NSRunLoop currentRunLoop];
[runLoop addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
BOOL done = NO;
while (!done) {
@autoreleasepool {
[runLoop runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
// check termination status:
done = ...;
}
}
}
}
A few explanations:
[runLoop addPort:port]
ensures that the run loop has at least one event source, otherwise, the run loop may return prematurely.
The run loop returns after every processed event source. That is, you may check the status after something happened (a timer for example, scheduled on this run loop whose mode equals NSDefaultRunLoopMode
).
The inner autorelease pool is required, since [NSDate distantFuture]
returns an autoreleased object - this may stack up unless you have that autorelease pool.
Variable done
must be set from code which executes on this thread - otherwise, you need memory barriers or other synchronization primitives in order to ensure that the change made on a different thread is "visible" in this thread.
Upvotes: 1