Can macOS dynamically change QoS value for pthreads

I have observed that in my application, Even If I set the QoS value of all the thread created to USER_INTERACTIVE, the OS is producing a warning "Thread running at User-Interactive QoS class waiting on a lower QoS thread running at Default QoS class. Investigate ways to avoid priority inversions".

I am aware that it is not right to set all threads as USER_INTERACTIVE QoS, but If we assume this case for once, then it means that the OS can dynamically change the QoS of the threads even if we are explicitly setting it. Is this the correct understanding?

Also, the main thread has QoS value USER_INTERACTIVE, then is it the case that its child threads will inherit the QoS value from the parent thread, If we are not setting any QoS for a pthread?

Replies

it means that the OS can dynamically change the QoS of the threads even if we are explicitly setting it.

Well, it depends on your perspective. There’s a QoS value that you control and priority value that’s initially derived from that QoS but can differ due to priority boosting. If you have a high QoS thread waiting on a resource held by a low QoS thread, the system will boost the priority of the low QoS thread to minimise the impact of this priority inversion.

Also, the main thread has QoS value USER_INTERACTIVE

That’s not always the case. Check out the doc comments for qos_class_main.

is it the case that its child threads will inherit the QoS value from the parent thread

No. Consider the code below. I put it in a command-line tool project and the resulting tool prints:

main: userInteractive
child: default

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

import Darwin

extension qos_class_t {
    var name: String {
        switch self {
        case QOS_CLASS_USER_INTERACTIVE: return "userInteractive"
        case QOS_CLASS_USER_INITIATED: return "userInitiated"
        case QOS_CLASS_DEFAULT: return "default"
        case QOS_CLASS_UTILITY: return "utility"
        case QOS_CLASS_BACKGROUND: return "background"
        case QOS_CLASS_UNSPECIFIED: return "unspecified"
        default: return "\(self.rawValue)?"
        }
    }
}

func main() {
    print("main:", qos_class_self().name)
    var t: pthread_t? = nil
    let err = pthread_create(&t, nil, { _ in
        print("child:", qos_class_self().name)
        return nil
    }, nil)
    assert(err == 0)
    let err2 = pthread_join(t!, nil)
    assert(err2 == 0)
}

main()