为什么自动释放的NSTask会无限期地阻止NSOperation线程上的runloop?

时间:2010-07-21 00:03:45

标签: objective-c cocoa multithreading nsoperation nstask

我试图从NSTask内部发起NSOperation

这是一个very simple app我已经把它们放在一起来展示这个问题。单击该按钮时,NSOperation排队。它设置NSRunLoop,并调用一个调用NSTask的方法。任务非常简单 - 只需启动/bin/sleep两秒钟(足以在事情正常工作时轻松查看微调器)。

该应用程序的工作方式与广告相同,但如果您将TaskPerformer.m的第23行更改为autorelease,(抱歉,我是新海报,因此我无法直接链接)或完全注释掉(因此泄漏NSTask对象),NSOperation的线程永远不会退出。它的主要runloop似乎阻止某事。

现在,这里的问题是双重的。首先,我不明白为什么我的线程会阻塞,而且,如果我打开这个应用程序的垃圾收集,同样的行为表现出来。因为我无法手动释放NSTask,所以线程无论如何都会阻塞。

如果有人能告诉我发生了什么事,我会永远感激不尽!

2 个答案:

答案 0 :(得分:4)

我在您发布的示例项目中看到了几个不同的问题。在TaskPerformer.m中,您有:

[task waitUntilExit];
[task launch];

{/ 1}}调用意味着在启动任务后调用,并且只是在任务完成之前阻塞并不执行任何操作。如果您只关心等待任务完成,而不是关于从中获取输出,那么您应该只需拨打waitUntilExit后跟launch,而不必费心去做运行循环。

如果您确实希望从任务中获取输出,那么您将需要获取其waitUntilExit,默认情况下应该返回standardOutput的实例。然后,您可以调用NSFileHandlereadDataOfLength:,两者都会在数据可用时阻止并返回流程中的数据。

因为这一切都将在后台线程中完成,所以这些方法可以阻塞,但是你不想在主线程上做同样的事情,因为这会锁定接口的用户,直到任务完成。如果您在主线程上执行此操作,则需要使用readDataToEndOfFile的{​​{1}}和朋友。但是对于后台线程,使用NSFileHandle时不一定非常必要。

答案 1 :(得分:1)

我弄清楚这里发生了什么。原来我对[runLoop run]的调用正在设置循环并无限期地运行它。它永远不会落入while (!done)循环。事实证明,在调用run之后,NSRunLoop将一直运行,直到它没有更多输入。在release上调用NSTask导致了这种情况,所以(非常偶然)我的runloop退出了。

解决方案是删除[runLoop run]并依赖我自己的while循环。希望这有助于其他人!