如何在主线程上安全地使用[NSTask waitUntilExit]?

时间:2016-01-25 16:02:41

标签: multithreading cocoa nstask

我有一个多线程程序,需要同时运行许多可执行文件并等待其结果。

我在[nstask waitUntilExit]中使用NSOperationQueue在非主线程上运行它(在主线程上运行NSTask是完全不可能的。)

我的程序随机崩溃或遇到断言失败,崩溃堆栈总是指向由waitUntilExit运行的runloop,它执行各种回调和处理程序,包括-IMHO错误-KVO和bindings updating the UI,这导致它们在非主线程上运行(它是probably the problem described by Mike Ash

如何安全使用waitUntilExit

使用KVO和IB绑定来防止它们被处理时,waitUntilExit本质上是不可用的问题,还是我需要做一些特殊的事情(除了在主线程上显式调度我的回调)运行waitUntilExit的错误线程?

2 个答案:

答案 0 :(得分:4)

正如Mike Ash指出的那样,你无法在随机的runloop上调用waitUntilExit。它很方便,但不起作用。你必须在“这实际上方便吗?”的计算中加入“不起作用”。

但是,您可以在10.7+中使用terminationHandler。它不会泵送runloop,因此不应该产生这个问题。您可以使用以下某些内容重新创建waitUntilExit(未经测试;可能无法编译):

dispatch_group group = dispatch_group_create();
dispatch_group_enter(group);
task.terminationHandler = ^{ dispatch_group_leave(group); };
[task launch];
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

// If not using ARC:
dispatch_release(group);

答案 1 :(得分:0)

很难说没有你正在做什么的一般背景......

通常,您无法从非主线程更新接口。因此,如果您在非主线程和更新UI中观察到NSTasks的一些KVO通知,那么您就错了。

在这种情况下,您可以通过简单的

来解决问题
-[NSObject performSelectorOnMainThread:];

或类似的想要更新UI。

但至于我更优雅的解决方案:

  1. 用maxConcurentOperationsCount = 1(所以FIFO队列)编写分离的NSOperationQueue并编写NSOperation的子类,它将执行NSTask并通过委托方法更新UI。这样,您将控制应用程序中执行任务的数量。 (或者你可以停止所有这些或其他)

  2. 但我认为,问题的高级解决方案是privileged helper tool。使用这种方法,您将获得两个主要好处:您的NSTask将在分离的过程中执行,并且您将拥有执行任务的root权限。

  3. 我希望我的答案能解决你的问题。