如何正確結束驅動RunLoop的NSThread

不負責任的apple sample

Apple的Sample說可以輪循線程是否應該退出,但是有bug

see:documentation/Cocoa/Conceptual/Multithreading/CreatingThreads/CreatingThreads.html

- (void)threadRuntime:(id)arg
{
    @autoreleasepool {
        GXLog(@"Thread created............>>>>>>>>>>>>>>>>>>>>>>");
        NSRunLoop *rl = [NSRunLoop currentRunLoop];
        
        [_target performSelector:_selector withObject:arg];
        [_target release];
        _target = nil;
        
        BOOL exitNow = NO;
        NSMutableDictionary *threadDict = [[NSThread currentThread] threadDictionary];
        [threadDict setValue:[NSNumber numberWithBool:exitNow] forKey:@"ThreadShouldExitNow"];
        
        NSDate *date = [NSDate date];
        while (!exitNow) {
            [rl runUntilDate:date];
            exitNow = [[threadDict valueForKey:@"ThreadShouldExitNow"] boolValue];
        }

        [_thread release];
        _thread = nil;
        
        GXLog(@"Thread Exited............<<<<<<<<<<<<<<<<<<<<<<");
    }
}

Instruments進行Time Profile是這樣的:


做的題外的修改,如果這樣輪詢

        while (!exitNow) {
            [rl runUntilDate:[NSDate date]];
            exitNow = [[threadDict valueForKey:@"ThreadShouldExitNow"] boolValue];
        }

內存佔用很恐怖

[NSDate date] autorelease來不及釋放,程序最終會因爲內存耗盡被系統幹掉。


使用CFRunLoopRun/CFRunLoopStop正確結束NSThread

一切皆因輪詢而起,那就破了輪詢

- (void)threadRuntime:(id)arg
{
    @autoreleasepool {
        GXLog(@"Thread created............>>>>>>>>>>>>>>>>>>>>>>");
        [_target performSelector:_selector withObject:arg];
        [_target release];
        _target = nil;
        
        CFRunLoopRun();
                
        [_thread release];
        _thread = nil;
        
        GXLog(@"Thread Exited............<<<<<<<<<<<<<<<<<<<<<<");
    }
}

- (void)stop
{
    if (!_thread) {
        return;
    }
    
    CFRunLoopStop(CFRunLoopGetCurrent());
}

千萬小心,stop會直接停止當前線程得RunLoop,這要求在RunLoop所在的線程執行stop, 實際情況可能在其它線程調用stop。


小結

雖然cocoa&xcode有很多利器,但是能不用多線程還是別用吧。



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章