IOS - Objective-C - How to stop NSThread when it waits?

I have nsthread, a while loop inside this. It gets objects from the "thread safe" queue in the main method. When I leave the UIViewController that contains this nsthread object, I call the nsthread cancel method, but it does not stop because it is blocked by the "queueLock" NSCondition. When I go back to this UIViewController, a new nsthread will be created and get the objects from the queue, but the previous thread still exits and they both try to use the same object from the queue, and this causes a memory management problem. My question is, how should I stop this thread when I leave the UIViewController.

The main NSThread method:

NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
while ([self isCancelled] == NO) {
    RenderRequest *renderRequest = [queue get];
    [self doRender:renderRequest];
    [renderRequest release];    
}

[pool drain];

      

This is the get method of the queue class:

- (id) get {
    id toRet = nil;
    [queueLock lock];
    @try {
       while ([queueContents count] == 0) {
            [queueLock wait];
        }

        toRet = [queueContents lastObject];
        [queueContents removeLastObject];
    }

    @finally {
         [queueLock unlock];
         return toRet;
    }
}

      

Thank!

+3


source to share


2 answers


I wrote a simple demo, hope it can help you :)

demo.h

#import <Foundation/Foundation.h>

@interface test : NSObject
{
    NSCondition *queueCondition;
    NSThread *queueThread;

    NSMutableArray *queueTask;

    NSTimer *timer;
}
- (id)init;
@end

      



demo.m

#import "demo.h"

@interface demo (PrivateMethods)
- (void)threadTest;
- (void)cancelThread;
- (void)addTask;
@end


@implementation demo

- (id)init
{
    self = [super init];
    if (self) {
        if (!queueThread) {
            if (!queueCondition) {
                queueCondition = [[NSCondition alloc] init];
            }

            if (!queueTask) {
                queueTask = [[NSMutableArray alloc] initWithCapacity:5];
            }

            queueThread = [[NSThread alloc] initWithTarget:self selector:@selector(threadTest) object:nil];
            [queueThread start];

            [self performSelector:@selector(cancelThread) withObject:nil afterDelay:10];

            if (!timer) {
                timer = [[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(addTask) userInfo:nil repeats:YES] retain];
            }
        }
    }
    return self;
}

- (void)dealloc
{
    [queueThread release];
    [queueCondition release];
    [queueTask release];
    [timer invalidate];
    [timer release];
    [super dealloc];
}

- (void)threadTest
{
    NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
    while (![[NSThread currentThread] isCancelled]) {
        [queueCondition lock];
        [queueCondition wait];

        if ([queueTask count] == 0) {
            [queueCondition unlock];
            continue;
        }

        NSString *str = nil;
        while ((str = [queueTask lastObject])) {
            NSLog(@"getTask: %@", [queueTask lastObject]);
            [queueTask removeLastObject];

        }

        [queueCondition unlock];
    }
    NSLog(@"threadTest end");
    [pool drain];
}

- (void)addTask
{
    [queueCondition lock];
    if (!queueTask) {
        queueTask = [[NSMutableArray alloc] initWithCapacity:5];
    }
    [queueTask addObject:@"new task"];
    [queueCondition signal];
    NSLog(@"add: new task");
    [queueCondition unlock];
}

- (void)cancelThread
{
    [timer invalidate];

    [queueThread cancel];

    [queueCondition lock];
    [queueCondition signal];
    [queueCondition unlock];
}
@end

      

+1


source


- (id) get
{
    id toRet = nil;
    [queueLock lock];
    @try
    {
        while ([queueContents count] == 0)
        {
            [queueLock wait];
            if ([self isCancelled]) return nil; // stop waiting
        }

        toRet = [queueContents lastObject];
        [queueContents removeLastObject];
    }
    @finally
    {
         [queueLock unlock];
         return toRet;
    }
}

      

main topic



NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

while ([self isCancelled] == NO)
{
    RenderRequest *renderRequest = [queue get];
    if (renderRequest == nil) break; // should stop
    [self doRender:renderRequest];
    [renderRequest release];    
}

[pool drain];

      

then you can cancel the thread and notify queueLock to stop waiting

0


source







All Articles