In main I spawn a new NSThread, and at a later point in main when a condition is met I want to stop the thread. How?

StackOverflow https://stackoverflow.com/questions/21142381

Question

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?

Was it helpful?

Solution

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

OTHER TIPS

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top