Почему автоматически выпущенный NSTask блокирует runloop в потоке NSOperation на неопределенный срок? - PullRequest
1 голос
/ 21 июля 2010

Я некоторое время пытался запустить NSTask из NSOperation.

Вот очень простое приложение , которое я собрал, чтобы продемонстрировать проблему,Когда вы нажимаете кнопку, NSOperation ставится в очередь.Он устанавливает NSRunLoop и вызывает метод, который вызывает NSTask.Задача действительно проста - она ​​просто запускает /bin/sleep в течение двух секунд (этого достаточно, чтобы легко видеть счетчик, когда все работает правильно).

Приложение работает так, как объявлено, однако, если вы измените строку 23 в TaskPerformer.m к autorelease, (извините, я новый автор, поэтому я не могу напрямую связать его) или закомментируйте его полностью (таким образом, пропуская объект NSTask), поток NSOperation никогда не завершится.Кажется, что основной цикл запуска чего-то блокирует.

Теперь проблема здесь двоякая.Во-первых, я не понимаю, почему мой поток блокирует, но, более того, если я включаю сборку мусора для этого приложения, то же самое поведение проявляется.Поскольку у меня нет возможности вручную выпустить NSTask, поток блокируется независимо от того, что.

Если бы кто-то мог сказать мне, что происходит, я был бы бесконечно благодарен!

Ответы [ 2 ]

4 голосов
/ 21 июля 2010

Я вижу несколько разных проблем в примере проекта, который вы опубликовали.В TaskPerformer.m у вас есть:

[task waitUntilExit];
[task launch];

Вызов waitUntilExit предназначен для вызова после запуска задачи и будет просто блокировать и ничего не делать, пока задача не будет завершена.Если вы заботитесь только о том, чтобы дождаться завершения задачи, а не о получении результата от нее или чего-либо еще, тогда вы можете просто вызвать launch с последующим waitUntilExit и не беспокоиться о том, чтобы возиться с циклом выполнения вall.

Если вы все же хотите получить выходные данные задачи, вам нужно получить ее standardOutput, которая по умолчанию должна вернуть вам экземпляр NSFileHandle.Затем вы можете вызвать readDataOfLength: или readDataToEndOfFile, которые заблокируют и вернут данные из процесса, когда они будут доступны.

Поскольку все это в любом случае будет выполняться в фоновом потоке, все в порядке, что эти методы блокируются, но вы не захотите делать то же самое в основном потоке, так как это заблокируетинтерфейс для пользователя, пока задача не была выполнена.Если вы сделали это в главном потоке, вы бы хотели использовать NSFileHandle readInBackgroundAndNotify и друзей.Однако для фонового потока использование NSRunLoop на самом деле не обязательно.

1 голос
/ 22 июля 2010

Я понял, что здесь происходит. Оказывается, мой звонок [runLoop run] настраивал цикл и выполнял его бесконечно. Он никогда не падал в петлю while (!done). Оказывается, что после вызова run, NSRunLoop будет работать, пока у него больше не будет входов. Вызов release на моем NSTask привел именно к этому сценарию, поэтому (совершенно случайно) мой runloop завершился.

Решением было удалить [runLoop run] и просто положиться на мой собственный цикл while. Надеюсь, это поможет кому-то еще!

...