目标C:线程之间自动释放的对象?

时间:2013-11-06 01:40:30

标签: ios nsthread autorelease

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

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

顺便说一句,这本来是一个面试问题。面试官坚持认为,自动释放的对象不能被授予另一个线程。他似乎对此感到生气。在技​​术访谈中越来越多,我遇到了相信他们知道一切的人。

3 个答案:

答案 0 :(得分: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];
    }
}

然而,如果第二个线程无法释放对象并且难以维护代码(保留/释放很难平衡),这可能会导致内存泄漏。

答案 1 :(得分:0)

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

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

让我们考虑一下人们使用-performSelector:onThread:withObject:waitUntilDone:在另一个线程上执行事物的常用方法。如果waitUntilDone为false,则此函数将接收器,选择器和参数存储在某种对象中,以等待另一个线程准备好执行它。因此,当将接收器和物体放入该结构中时,该功能必须负责保持接收器和物体,并在结构被破坏时释放它。事实确实如此 - 如果您阅读the pre-ARC documentation for the method,它会说“此方法会保留接收器和arg参数,直到执行选择器之后。”

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

答案 2 :(得分:-1)

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

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