2

I read that dispatch_sync() would block the current thread and won't return back to it until the task that one would like to do synchronously was finished on a serial queue that dispatch_sync() requires to work on.

So basically it would stop the current thread and perform the task it has.

If that, why bother having another queue for this kind of task, why cannot we just put the task on the current thread.

After all, doing the task would block the current thread anyway.

Since dispatch_sync() wouldn't open another thread, then why do we bother opening another queue to do the task rather than doing it on the current queue/thread?

Hope I describe my confusion here clearly.

I am here comparing using dispatch_sync() on another queue with using the current thread/queue directly, so what I would like to know is in what use case, using dispatch_sync() on another queue would be better than using only the current queue.

This should be relevant to thread-safe and synchronization issue.

bolizhou
  • 1,208
  • 1
  • 13
  • 31
  • Possible duplicate of [Difference between dispatch\_async and dispatch\_sync on serial queue?](http://stackoverflow.com/questions/19822700/difference-between-dispatch-async-and-dispatch-sync-on-serial-queue) – holex Aug 18 '16 at 08:13

2 Answers2

2

There could be many reasons why you would want to do this, but one common use case is to guard a critical section of code. Say you have multiple threads that want to update an array. Arrays aren't thread safe so this could lead to the array becoming corrupted.

By using a dispatch_sync on to a serial queue and updating the array inside the dispatched block you can ensure that only one thread updates the array at a time. You need a synchronous dispatch because you want the requesting thread to wait until the array has been updated before continuing.

For example, here is a simple queue class that uses a serial dispatch queue to ensure thread safety when the underlying array is updated:

class Queue<T> {

    private var theQueue = [T]()

    private var dispatchQ = dispatch_queue_create("queueQueue", DISPATCH_QUEUE_SERIAL);

    func enqueue(object:T) {
        dispatch_sync(self.dispatchQ) {
            self.theQueue.append(object)
        }
    }

    func dequeue() -> T? {
        return self.dequeue(true)
    }

    func peek() -> T? {
        return self.dequeue(false)
    }

    private func dequeue(remove: Bool) -> T? {
        var returnObject: T?
        dispatch_sync(self.dispatchQ) {
            if !self.theQueue.isEmpty {
                returnObject = self.theQueue.first
                if (remove) {
                    self.theQueue.removeFirst()
                }
            }
        }

        return returnObject
    }

    func isEmpty() -> Bool {
        return self.theQueue.isEmpty
    }
}
Paulw11
  • 108,386
  • 14
  • 159
  • 186
  • So if I dispatch a task on a global/custom serial queue synchronously, this task would be thread-safe? What if I dispatch more than one task on the same serial queue synchronously? Would that be fine? – bolizhou Aug 18 '16 at 07:19
  • I wouldn't say that the task is thread-safe, rather than you can use a serial dispatch queue to make updates to an object, such as an array, thread safe. But you need to be disciplined. If you don't *always* dispatch the updates onto the serial queue then corruption can still occur. You can dispatch any number of tasks onto a serial queue. A serial queue will only execute a single task at a time (hence its name). In the case of a dispatch_sync the dispatching threads will be blocked until *their* task has completed – Paulw11 Aug 18 '16 at 07:55
  • I see your update. So this `queue` model of yours, it uses `dispatch_sync()` to protect `critical section` of dequeuing and enqueuing code. May I say that `dispatch_sync()` can replace `NSLock` or `NSRecursiveLock` or `@synchronization{}` on some level or in some cases? – bolizhou Aug 19 '16 at 01:33
  • Yes, that is a common use for it. `dispatch_sync` alone isn't enough. You need to use a serial queue so that you know only one block will execute at a time – Paulw11 Aug 19 '16 at 01:34
0

dispatch_sync() would basically block the current thread until all it's tasks are done-Correct!

Why we have other methods like dispatch_async() is because in certain situations, we need to execute some tasks with parallelism or at least "near parallelism". Suppose you need to download a substantial file over the network. If we're to do this on the main thread, then all the UI will freeze until the download finishes. This is because, the UI needs to be drawn continuously so that the user experience is maintained well! You wouldn't like to see a frozen UI whenever you click a download button. Do you?

In such cases, we can use dispatch_async() so that the network task (downloading the file) gets executed on a different thread. Now, unlike the above case, the processor would very quickly switch from downloading the file to updating the UI. Therefore, the app will remain responsive. In other words, you will be able to use the app with good user experience.

Hope you're clear on why we need queues other than the main queue!

Ruchira Randana
  • 4,021
  • 1
  • 27
  • 24
  • The question isn't "why do we need other queues?" but "why would you dispatch synchronously onto another queue? - Since the dispatch_sync will block the calling queue, why not just execute the code inline?" – Paulw11 Aug 18 '16 at 23:15