NSThread对象保留了两次?

发布于 2024-08-14 19:34:27 字数 1322 浏览 10 评论 0原文

我有一个派生自 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 的呢?

请注意,NSThread 的文档仅提到使用 detachNewThreadSelector:toTarget:withObject: 时保留。

I have a class derived from 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

Elsewhere (inside a C++ function), I create an instance:

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

My understanding is that the retain-count should now be 1.
In another C++ function, I want to stop and deallocate the thread:

[m_thread release];

Yet the dealloc method is not called. If I instead do:

[m_thread release];
[m_thread release];

then dealloc is called which implies the retain-count was 2. But how did it get to be 2?

Note that the documentation for NSThread only mentions retaining when using detachNewThreadSelector:toTarget:withObject:.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

千鲤 2024-08-21 19:34:27

框架本身保留线程的所有权。这是必要的,以便线程对象在 main 方法执行时不会消失。如果你想停止一个线程,那么你的做法是错误的。您必须提供某种线程间通信来向线程的 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());
}

The framework itself keeps ownership of the thread. This is necessary so that the thread object doesn't go away while the main method is executing. If you want to stop a thread, you are doing it the wrong way. You must provide some sort of inter-thread communication to signal the thread's main method that it should stop whatever it is doing, clean up, and exit. Once that happens, relinquishing your ownership of the thread will cause the thread to dealloc. You should never simply over-release something to get it to "go away". If you are doing that, you are almost certainly not using the provided objects the way they are meant to be used, as in this case.

A very simple example to cancel your thread might be:

- (void)finishThread
{
  if( [NSThread currentThread] != self ) // dispatch this message to ourself
    [self performSelector:@selector(finishThread) onThread:self withObject:nil waitUntilDone:NO];
  else
    CFRunLoopStop(CFRunLoopGetCurrent());
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文