Use dispatch queues for synchronization

Switch from using `@synchronized` and `NSLock` for synchronization to using dispatch queues.

* Instead of mutual exclusion with `NSLock`, use a serial queue and `dispatch_sync` around critical sections.
* Instead of `@synchronized` for mutable object synchronization, use a concurrent queue with `dispatch_sync` around reads and `dispatch_barrier_async` around writes.

@jnjosh Please review. This is arguably better than before. It’s very slightly more performant, but more importantly, it’s consistent. Also, merge this before pull request #3 (task graph completion).
It just got fulfilled, not finished. There are basically two cases to worry about: has the task been tried or not. If the task has never been run (because it’s prereqs aren’t finished) retrying it does nothing. If it has been run, it failed, because it wasn’t fulfilled. Retrying it will allow it to pass now, thus enabling it’s dependencies to run.

, you need to retry it, which will check to see if it can run, and if so, set the state to finished instead of failed. If it has never been run (dependencies aren’t finished), nothing will happen.