如果我有一个自动释放的对象,我需要将它提供给另一个线程,那么最好的方法是什么?
假设我有一个在线程0中自动释放的对象。我告诉线程1关于这个对象并保留它因为它需要它。之后它就完成了,它会释放它。没问题。当线程0再次运行并清空其自动释放池时,它会看到保留计数为1,因为它是一个自动释放的对象,所以它是deallocs。一切都很好,因此线程并不重要。正确?
顺便说一句,这本来是一个面试问题。面试官坚持认为,自动释放的对象不能被授予另一个线程。他似乎对此感到生气。在技术访谈中越来越多,我遇到了相信他们知道一切的人。
答案 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)
别。将拥有的引用传递给另一个线程。另一个线程将获取对象的所有权,并在完成后释放它。
使用自动释放的对象,您无法分辨何时发送线程自动释放池将被耗尽,并且无法确定它是否会在接收线程获取之前耗尽。