Question

My Qt4 code uses some QThread instances which operate on a common data structure which contains some QString fields. It can be boiled down to the following:

My data structure:

class My : public QObject{
    Q_OBJECT
public:
    QString foo;
};

The thread implementation:

class Thr : public QThread{
public:
    My* my;
protected:
    void run(){
        while (true){
            QString copy = my->foo;
            QString bar = copy.toUpper();
            my->foo = bar.toLower();
        }
    }
};

This is a test application written for my research on the problem. Of course, it does not do anything actually useful :)

If I initialize one instance of My and start one thread with that instance, everything is fine. But when I start a second one with the same My instance, it crashes with different messages looking like some heap/stack/whatever corruption.

Is that normal? I am aware about multithreading issues in general and also about Qt's QMutex, which can avoid the problem. But as far as I understood the Qt documentation correctly, I am allowed to use it this way. I do not operate on the same instance of QString simultaneously (possibly I do due to some fancy implicit sharing mechanism - but the documentation states that this is fully transparent for the user?!).

As mentioned, my question is not about how to rewrite the code, but what piece of "Beginning with Qt 4, implicit shared classes can safely be copied across threads, like any other value classes. They are fully reentrant. The implicit sharing is really implicit." (http://qt-project.org/doc/qt-4.8/threads-modules.html) I have misunderstood.

Was it helpful?

Solution

As noted in the comment, you are probably trying to write the same data from different threads. I am writing "probably" only because you have not shared the usage of your QThread subclass.

As pointed out in the comment, not even an assignment is guaranteed by the C++ standard to be thread-safe for classes like your Object subclass with a QString inside.

You could use std::atomic as per hint, although it has only been available since C++11. A more cross-solution would be to use QMutex for your scenario, or probably evn better to use the RAII solution with QMutexLocker which will take care of the unlocking for you, automatically. So you would be something like the code below.

class Thr : public QThread{
public:
    My* my;
    QMutex mutex; // <--- first addition
protected:
    void run(){
        while (true){
            QString copy = my->foo;
            QString bar = copy.toUpper();
            QMutexLocker locker(&mutex); // <--- second addition
            my->foo = bar.toLower();
        }
    }
};

Of course, the recommended solution depends on further factors, for instance, you could also redesign your program not to use a pointer depending on the exact use case at hand, et al.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top