Search code examples
qtc++11thread-local-storage

QThreadStorage vs C++11 thread_local


As the title suggests: What are the differences. I know that QThreadStorage existed long before the thread_local keyword, which is probably why it exists in the first place - but the question remains: Is there any significant difference in what they do between those two (except for the extended API of QThreadStorage).

Im am assuming a normal use case of a static variable - as using QThreadStorage as non static is possible, but not recommended to do.

static thread_local int a;
// vs
static QThreadStorage<int> b;

Solution

  • Well, since Qt is open-source you can basically figure out the answers from the Qt sources. I am currently looking at 5.9 and here are some things, that I'd classify as significant:

    1) Looking at qthreadstorage.cpp, the get/set methods both have this block in the beginning:

    QThreadData *data = QThreadData::current();
    if (!data) {
        qWarning("QThreadStorage::set: QThreadStorage can only be used with threads started with QThread");
        return 0;
    }
    

    So (an maybe this has changed/will change) you can't mix QThreadStorage with anything else than QThread, while the thread_local keyword does not have similar restrictions.

    2) Quoting cppreference on thread_local:

    thread storage duration. The object is allocated when the thread begins and deallocated when the thread ends.

    Looking at qthreadstorage.cpp, the QThreadStorage class actually does not contain any storage for T, the actual storage is allocated upon the first get call:

    QVector<void *> &tls = data->tls;
    if (tls.size() <= id)
        tls.resize(id + 1);
    void **v = &tls[id];
    

    So this means that the lifetime is quite different between these two - with QThreadStorage you actually have more control, since you create the object and set it with the setter, or default initialize with the getter. E.g. if the ctor for the type could throw, with QThreadStorage you could catch that, with thread_local I am not even sure.

    I assume these two are significant enough not to go any deeper.