简体   繁体   English

iOS - Objective-C - 当NSThread正在等待时如何停止?

[英]iOS - Objective-C - How to stop NSThread, when it's waiting?

I have an nsthread, a while loop within this one. 我在这一个中有一个nsthread,一个while循环。 It's getting objects from a "thread-safe" queue in the main method. 它从主方法中的“线程安全”队列中获取对象。 When I leave the UIViewController, which contains this nsthread object, I call the nsthread cancel method, but it doesn't stop, because it's locked by the "queueLock" NSCondition. 当我离开包含这个nsthread对象的UIViewController时,我调用了nsthread取消方法,但它没有停止,因为它被“queueLock”NSCondition锁定。 When I go back to this UIViewController a new nsthread will be created and gets the objects form the queue, but the previous thread still exits and both of them try to use the same object from the queue, and this causes a memory management problem. 当我回到这个UIViewController时,将创建一个新的nsthread并从队列中获取对象,但是前一个线程仍然退出,并且它们都尝试使用队列中的相同对象,这会导致内存管理问题。 My question is how should I stop this thread, when I leave the UIViewController. 我的问题是当我离开UIViewController时应该如何停止这个线程。

NSThread main method: NSThread主要方法:

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: 这是队列类的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;
    }
}

Thanks! 谢谢!

I wrote a simple demo, hope this can help you :) 我写了一个简单的demo,希望这可以帮到你:)

demo.h demo.h

#import <Foundation/Foundation.h>

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

    NSMutableArray *queueTask;

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

demo.m 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
- (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;
    }
}

thread main 主线

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 然后你可以取消线程并通知queueLock停止等待

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM