iOS - Objective-C - Как остановить NSThread, когда он ждет? - PullRequest
3 голосов
/ 29 марта 2012

У меня есть nsthread, цикл while внутри этого.Он получает объекты из «поточно-ориентированной» очереди в методе main.Когда я покидаю UIViewController, который содержит этот объект nsthread, я вызываю метод отмены nsthread, но он не останавливается, потому что он заблокирован NSCondition «queueLock».Когда я вернусь к этому UIViewController, будет создан новый nsthread, который получит объекты из очереди, но предыдущий поток по-прежнему завершается, и оба они пытаются использовать один и тот же объект из очереди, что вызывает проблему с управлением памятью.У меня вопрос, как мне остановить этот поток, когда я покидаю UIViewController.

Основной метод NSThread:

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

[pool drain];

Это метод get класса очереди:

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

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

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

Спасибо!

Ответы [ 2 ]

1 голос
/ 29 марта 2012

Я написал простую демонстрацию, надеюсь, это поможет вам:)

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
0 голосов
/ 29 марта 2012
- (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;
    }
}

главный поток

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];

тогда вы можете отменить поток и уведомить queueLock о прекращении ожидания

...