If you submit a task with a higher quality of service than the queue has, the queue’s level will increase. Not only that, but all the operations enqueued will also have their priority raised as well.
I was trying to test that situation by using the following code:
The QoS is still .utility rather than .userInteractive.
2. In chapter 5, “Priority Inversion” part,
The more common situation wherein priority inversion occurs is when a higher quality of service queue shares a resource with a lower quality of service queue
the example code shows the case, but I got confused about common resources they are sharing.
They didn’t access anything except the print function. Wait, is the print function the common resource?
The example code
high.async {
// Wait 2 seconds just to be sure all the other tasks have enqueued
Thread.sleep(forTimeInterval: 2) semaphore.wait()
defer { semaphore.signal() }
print("High priority task is now running")
}
for i in 1 ... 10 { medium.async {
let waitTime = Double(exactly: arc4random_uniform(7))! print("Running medium task \(i)") Thread.sleep(forTimeInterval: waitTime)
} }
low.async { semaphore.wait()
defer { semaphore.signal() }
print("Running long, lowest priority task")
Thread.sleep(forTimeInterval: 5) }
Apple determines when to change the priority. It won’t happen just because you do it once. There’s no clearly defined algorithm for when it decides to make that change. Best guess is that if you are abusing the queue, and other things are using a similar queue, it might decide to move it.
For your second question. There’s no specific element being shared here…semaphore is the shared resource control. The what you’re sharing iOS has no idea. But you control access to that resource via the semaphore.
So for this example you can think of the print statement as the common resource, sure.
I still don’t understand the example given in the book as I would like to. The author of the book says,
The more common situation wherein priority inversion occurs is when a higher quality of service queue shares a resource with a lower quality of service queue. When the lower queue gets a lock on the object, the higher queue now has to wait.
But I still don’t grasp the example fully.
let high = DispatchQueue.global(qos: .userInteractive)
let medium = DispatchQueue.global(qos: .userInitiated)
let low = DispatchQueue.global(qos: .background)
let semaphore = DispatchSemaphore(value: 1)
high.async {
// Wait 2 seconds just to be sure all the other tasks have enqueued
Thread.sleep(forTimeInterval: 2)
semaphore.wait()
defer { semaphore.signal() }
print("High priority task is now running")
}
for i in 1 ... 10 {
medium.async {
let waitTime = Double(exactly: arc4random_uniform(7))!
print("Running medium task \(i)")
Thread.sleep(forTimeInterval: waitTime)
}
}
low.async {
semaphore.wait()
defer { semaphore.signal() }
print("Running long, lowest priority task")
Thread.sleep(forTimeInterval: 5)
}
Could you please explain the priority inversion in the given example again, but in another way?