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.