1

I have registered for a NSTaskDidTerminateNotification of a NSTask object. Everything works fine, but the task takes time to launch so i've moved the launching to background (with performSelectorInBackground).

  • the registration with notification center and the creation of the task itself takes place on the main thread
  • after a few seconds the task gets launched in background
  • notifications no longer arrive :(

Is there a way i could somehow adjust the code for the notifications to work again?

Marius
  • 3,976
  • 5
  • 37
  • 52
  • just in case, can you post the code for init, registration and the block code executed async – lead_the_zeppelin Nov 05 '13 at 01:16
  • @lead_the_zeppelin everything is pretty standard, async code is just the [task launch] command. I've tried moving notification registration there as well, but didn't work. Anyway, it does not matter now, because i'm now doing waitUntilExit after launch and after that i'm manually calling the method the notification center shouldv'e called. And it works again so i guess the problem is solved. – Marius Nov 05 '13 at 01:39

2 Answers2

1

first off NSTask is not thread safe. you need to take care when using an instance of it from separate threads or avoid it entirely.

secondly as far as I can tell NSNotifications are only delivered on the thread that the notification is posted on. The notification is posted by the NSTask object itself which is apparently terminating on a secondary thread, but you have registered for the notification on the main thread. See the docs for more info.

Could you simply handle the entire task and notification sequence on the background thread?

Brad Allred
  • 7,323
  • 1
  • 30
  • 49
  • Tried doing it on background thread, but the notification did not arrive. Anyway, i didn't wanna waste more time on this so i've just simply issued waitUntilExit in bg thread and that does the same thing for me, so the problem is fixed now. – Marius Nov 05 '13 at 20:46
1

NSTask registers a private run-loop source to monitor the task in the run loop of the thread on which it's launched. If that thread doesn't continue to exist and run its run loop, then Cocoa can't notice that the task has terminated. If Cocoa doesn't notice it, then it can't post the notification to your observer(s).

If the only thing you're doing with -performSelectorInBackground:... is invoking the -launch method of the task, then the thread doesn't stick around nor run its run loop. (Similarly, the worker threads that service GCD queues can't be relied upon to keep existing or run their run loops.) You could invoke a more complicated method in the background which launches the task and then runs the run loop, but that shouldn't be necessary.

Are you sure that launching the task is taking any appreciable amount of time? It really shouldn't. NSTask is designed so that tasks can be created, launched, and monitored on the main thread without making it unresponsive.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • it does take time, since the task is an "ssh" tunnel conenction and there's quite a few of them. I've solved the problem by waiting for task to finish manually (in background) and them "posting" a notification to main thread myself. Anyway, thank you for your explanation, i think it's very informative so i'll mark that as the answer. – Marius Nov 05 '13 at 20:48
  • The task may take time to run, but it shouldn't take much time to *launch*. \*shrug\* – Ken Thomases Nov 06 '13 at 02:18
  • Well, it does. 1-3 seconds. And since there's a few of those connections - the impact is pretty obvious :) – Marius Nov 06 '13 at 16:49