Search code examples
iosswiftconcurrencygrand-central-dispatch

GCD serial async queue vs serial sync queue nested in async


I have to protect a critical section of my code. I don't want the caller to be blocked by the function that can be time consuming so I'm creating a serial queue with background qos and then dispatching asynchronously:

private let someQueue = DispatchQueue(label: "\(type(of: self)).someQueue", qos: .background)

func doSomething() {
    self.someQueue.async { 
       //critical section
    }
}

For my understanding, the function will directly return on the calling thread without blocking. I've also seen somewhere dispatching first asynchronously on the global queue, the synchronously on a serial queue:

private let someQueue2 = DispatchQueue(label: "\(type(of: self)).someQueue2")

func doSomething() {
    DispatchQueue.global(qos: .background).async {
        self.someQueue2.sync { 
           //critical section
         }
    }
}

What's the difference between the two approaches? Which is the right approach?


Solution

  • In the first approach, the calling thread is not blocked and the task (critical section) passed in the async block will be executed in background.

    In the second approach, the calling thread is not blocked, but the "background" thread will be waiting for the sync block (critical section) execution which is executed by another thread.

    I don't know what you do in your critical section, but it seems first approach seems the best one. Note that background qos is quite slow, maybe use default qos for your queue, unless you know what you are doing. Also note that convention wants that you use bundle identifier as label for your queue. So something like this:

    private let someQueue = DispatchQueue(label: "\(Bundle.main.bundleIdentifier ?? "").\(type(of: self)).someQueue")