2009-12-08 119 views
0

我從NSThread派生的類:NSThread對象保留兩次?

@interface FSEventMonitorThread : NSThread { 
    FSEventStreamRef m_fseStreamRef; 
    CFRunLoopRef m_runLoop; 
} 

- (id) initWithStream: 
    (FSEventStreamRef)fseStreamRef; 

- (void) dealloc; 

- (void) main; 

@end 

@implementation FSEventMonitorThread 

- (id) initWithStream: 
    (FSEventStreamRef)fseStreamRef 
{ 
    if (self = [super init]) 
     m_fseStreamRef = fseStreamRef; 
    return self; 
} 

- (void) dealloc 
{ 
    CFRunLoopStop(m_runLoop); 
    FSEventStreamStop(m_fseStreamRef); 
    [super dealloc]; 
} 

- (void) main 
{ 
    m_runLoop = CFRunLoopGetCurrent(); 
    FSEventStreamScheduleWithRunLoop(
     m_fseStreamRef, m_runLoop, kCFRunLoopDefaultMode 
    ); 
    FSEventStreamStart(m_fseStreamRef); 
    CFRunLoopRun(); 
} 

@end 

在其他地方(一個C++函數內),我創建一個實例:

m_thread = [[FSEventMonitorThread alloc] initWithStream:m_fseStreamRef]; 

我的理解是,保留數現在應該是1。 在另一個C++函數,我想停下來,解除分配線程:

[m_thread release]; 

然而dealloc方法不被調用。如果我不是這樣做:

[m_thread release]; 
[m_thread release]; 

然後dealloc被稱爲這意味着該保留數是2,但它是怎麼得到是2?

請注意,當使用detachNewThreadSelector:toTarget:withObject:時,NSThread的文檔僅提及保留。

回答

3

框架本身保留線程的所有權。這是必要的,以便線程對象在main方法執行時不會消失。如果你想停止一個線程,你是在做錯誤的方式。您必須提供某種線程間通信,以指示線程的主要方法,即停止正在執行的任何操作,清理並退出。一旦發生這種情況,放棄對線程的所有權將導致線程解除分配。你不應該簡單地過度釋放某些東西來讓它「消失」。如果你這樣做,你幾乎可以肯定不會按照它們被使用的方式使用提供的對象,就像在這種情況下一樣。

一個非常簡單的例子來取消的線程可能是:

- (void)finishThread 
{ 
    if([NSThread currentThread] != self) // dispatch this message to ourself 
    [self performSelector:@selector(finishThread) onThread:self withObject:nil waitUntilDone:NO]; 
    else 
    CFRunLoopStop(CFRunLoopGetCurrent()); 
} 
+0

CFRunLoopRun()之前,不會返回CFRunLoopStop()被調用;因此,我的main()無法檢查isCancelled。我覆蓋了取消方法來調用CFRunLoopStop()。所以現在停止線程,我正在做[m_thread取消],然後是[m_thread發佈],並且工作。問題:重寫取消方法是一件好事嗎?文件沒有說不應該。 – 2009-12-08 19:04:30

+0

這取決於你在做什麼,但總的來說,我會說不,不這樣做。最簡單的方法是添加一個像finishThread這樣的方法;我會在我的答案中添加一個快速示例。在CFRunLoopRun()函數返回後,您還應該執行所需的清理。 – 2009-12-08 19:36:48