1

如果我有一个自动释放的对象并且我需要将它提供给不同的线程,那么最好的方法是什么?

假设我有一个在线程 0 中自动释放的对象。我将这个对象告诉线程 1,它会保留它,因为它需要它。稍后它完成,它释放它。没问题。当线程 0 再次运行并清空其自动释放池时,它看到保留计数为 1,并且因为它是一个自动释放的对象,所以它会释放。一切都很好,因此线程无关紧要。正确的?

顺便说一句,这最初是一个面试问题。面试官坚持认为不能将自动释放的对象提供给另一个线程。他似乎对此几乎生气了。在技​​术面试中,我越来越多地遇到相信自己无所不知的人。

4

3 回答 3

0

只要您遵循正常的 Cocoa 内存管理规则,就没有什么可担心的。只要您遵守规则,“将其提供给不同的线程”的每一种方式都可以正常工作。

几乎任何时候你“向不同的线程提供一些东西”,它都是异步的(除非你使用锁来做同步的跨线程执行或其他东西)。这意味着在该线程上的当前函数超出范围后,其他线程可能(并且可能)使用它。每当您存储需要超过当前执行的对象时,都需要保留它。如果您将它直接存储在实例变量或全局变量中,那么您有责任根据内存管理规则保留它。如果您将它存储在某种容器对象中,则该对象负责保留它。因此,如果您遵守规则,几乎没有什么可担心的。

让我们考虑一种人们在另一个线程上执行事物的常见方式,使用-performSelector:onThread:withObject:waitUntilDone:. 如果waitUntilDone为 false,此函数将接收器、选择器和参数存储在某种对象中,以等待其他线程准备好执行它。因此,该函数必须负责在将接收者和对象放入此结构时保留它,并在结构销毁时释放它。确实如此 - 如果您阅读该方法的 pre-ARC 文档,它会说“此方法保留接收器和 arg 参数,直到执行选择器之后。”

所以基本上内存管理规则就足够了——如果将对象存储在实例变量中,则需要保留它。如果你将它传递给其他函数,那么他们的工作就是照顾它。

于 2013-11-07T11:29:42.743 回答
0

您不应将自动释放的对象直接传递给其他线程。

在这段代码中

id _sharedVariable; // ivar
NSConditionLock *_lock;

- (void)thread1
{
    id objectNeedToPass = [[NSObject new] autorelease];
    [_lock lock];
    _sharedVariable = objectNeedToPass;
    [_lock unlockWithCondition:1];
}

- (void)thread2
{
    while (true)
    {
        [_lock lockWithCondition:1];
        id objectReceived = [_sharedVariable retain];
        [_lock unlockWithCondition:0]
        process(objectReceived );
        [objectReceived release];
    }
}

thread2 可能会看到_sharedVariable持有已释放的对象(并崩溃)

因为它可能会这样做

thread 1 create and autorelease object
thread 1 assign it to the shared variable
thread 1 release the object
object deallocated
thread 2 read the object
thread 2 retain the object - crash

要解决这个问题,你应该传递一个保留对象

id _sharedVariable; // ivar
NSConditionLock *_lock;

- (void)thread1
{
    id objectNeedToPass = [[NSObject new] autorelease];
    [_lock lock];
    _sharedVariable = [objectNeedToPass retain];
    [_lock unlockWithCondition:1];
}

- (void)thread2
{
    while (true)
    {
        [_lock lockWithCondition:1];
        id objectReceived = _sharedVariable;
        [_lock unlockWithCondition:0]
        process(objectReceived );
        [objectReceived release];
    }
}

但是,如果第二个线程未能释放对象并使代码难以维护(保留/释放难以平衡),这可能会导致内存泄漏

于 2013-11-06T02:41:18.307 回答
-1

不。将拥有的引用传递给另一个线程。另一个线程将获得该对象的所有权,并在完成后释放它。

使用自动释放对象,您无法判断发送线程自动释放池何时会被耗尽,也无法确定它是否会在接收线程获取它之前被耗尽。

于 2013-11-06T01:50:12.157 回答