1

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?

3
  • 2
    The second form seems like a misunderstanding by someone who doesn’t realize that a local dispatch queue can be made concurrent. Commented Dec 18, 2020 at 16:05
  • 1
    You should never call a dispatch_sync within a concurrent queue (which the global queue is) - especially when execution duration of the "critical section" can be long, since this can lead to "thread explosion". GCD was designed that an app creates as few threads a possible. So, this is actually an "anti pattern". So, the difference is, that approach 1 is a viable one, and approach 2 is wrong. Commented Dec 20, 2020 at 19:35
  • @CouchDeveloper I agree with you, in the legacy codebase I'm working on the first approach is being used in many situations so I was questioning my approach Commented Dec 21, 2020 at 9:57

1 Answer 1

1

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")
Sign up to request clarification or add additional context in comments.

2 Comments

In my critical section I'm writing a log in a file appending content. Thanks for your explanation and qos suggestion, do you stil recommend not using background?
Generally the lowest priority you should use is .utility. Background priority can be starved when the device is in a low power state.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.