views:

118

answers:

2

Yesterday I read somewhere that NSTask isn't thread safe and that bothers me a lot, because I'm running a NSTask within a NSThread and is so far not experiencing any threading issues with it.

My code is organized like this

A: main thread -> B: worker thread -> C: worker task

C: The worker task is a commandline program.
B: The worker thread can start/stop the worker task and send it commands.
A: The main thread can send commands to the worker thread.

If NSTask is supposed to be used only within the main thread, then I'm considering moving the NSTask start/stop code to the main thread, just to prevent possible threading issues.

Can NSTask be used outside the main thread?

And if not then what may be the threading issues with NSTask?

A: 

Yes, it can, but I suggest you using NSOperation. It's KVO-agnostic (unlike threaded NSTask). Also you may want to look into receptionist design pattern regarding KVO and threaded environment (in case you need KVO).

Eimantas
Please explain. Regaring NSOperation, yes I'm aware of it and what I'm doing is somewhat related, but this question is about using NSTask. I should add that I'm not sharing NSTask between threads.
neoneye
NSOperation and NSTask aren't comparable. NSOperation starts a thread; NSTask starts a process. You could have an operation that starts a task, but that gets back to the question neoneye asked, which is whether it's safe to use NSTask from a secondary thread.
Peter Hosey
+2  A: 

I read somewhere that NSTask isn't thread safe

That's not what that page says. It says that you'll get the process-terminated notification on the same thread you launched it from, which suggests that NSTask is aware of threads and tries to do the right thing.

The problem one of the editors of that page encountered was that they started their process from a thread, then let the thread die. That caused a crash because the framework was no longer able to deliver the process-terminated notification to the correct thread.

The Thread Safety Summary (bookmark that) says something similar, listing NSTask in a list of classes about which it says:

In most cases, you can use these classes from any thread as long as you use them from only one thread at a time. Check the class documentation for additional details.

The NSTask documentation doesn't say anything additional about threads, so it sounds like NSTask is one of the “most cases”: You can use a task from the thread you created it on. Don't use the same task on another thread, and (as noted above) make sure the thread lasts at least as long as the task process.

I will note, however, that in most cases, there is no need to run a task on a separate thread. Separate processes tend to run on other processors just as other threads in your process do, and the run loop does a good job of multiplexing many small events and keeping the UI responsive. You can use NSFileHandle's readInBackgroundAndNotify method if you need to read output from the task. You may be able to cut out your worker threads entirely.

The alternative is, as Eimantas suggested, to use NSOperation: Have an operation that simply starts a particular task and waits for that task to exit (perhaps synchronously reading output from it). The operation is complete when the task has exited.

Peter Hosey
yeah, a notification to a dead thread that may likely cause trouble. That cocoadev page made me suspicious so I had to be sure that wasn't something obvious I was missing. I'm using fileHandleWithNullDevice so I don't have to read in background, instead I'm using distributed objects in a bi-directional way so that I can send commands between the two tasks. The tasks are long running. Thank you for a most excellent answer.
neoneye