My tutorial on how to properly use QThreads



  • @JohnKaul: here you go: just published http://mayaposch.wordpress.com/2012/02/24/implementing-a-cookiejar-for-qtwebkit-qnetworkcookiejar-analysis/ :)

    @ddriver: Yeah, the WordPress WYSIWYG editor seems to love nuking indenting when I paste code into it. Found out about that recently. I'll correct it in this tutorial too.

    @KA51O: Thank you :) I had a lot of trouble figuring out how to do it and spent weeks trying to make it work for my own projects. I figured I'd save others the trouble and agony :D

    @Gerolf: I'd love to see it on the Wiki. Would save a lot of people the trouble of searching the entire 'net for this tutorial.



  • Hi Maya,

    welcome to Qt DevNet!

    [quote author="MayaPosch" date="1330098044"]
    @Gerolf: I'd love to see it on the Wiki. Would save a lot of people the trouble of searching the entire 'net for this tutorial.[/quote]

    You can add everything yourself. The wiki is open for everyone here on DevNet, there are no editors or the like (despite the fact that everyone can edit your article, of course). I'm looking forward to read from you. Regarding your threads post, we already have a very good wiki article on the topic: "Threads, Events and QObjects":/wiki/Threads_Events_QObjects - I think your samples and explanations would fit very good into that article, instead of a new article.



  • Hi Volker :)

    I could massively edit that article, I guess... or maybe there's a more subtle way to go about it? Being new here I would like some guidance :)



  • A massive edit wouldn't be the best way to go. You might want to contact "peppe":/member/5319, the original author of said wiki article, directly to discuss improvements. I didn't compare your text an the wiki page, but I could guess that you come to the same conclusions, basically. Maybe you want to start to incorporate your code samples as a start.

    If in doubt, you can alway start a new thread in the "Wiki Discussion":/forums/viewforum/16/ forum. And don't forget: The wiki has a history - if something goes seriously wrong, one can always roll back to a previous version.



  • Well, I don't think it hurts to have two entries on the same topic. I find that peppe's article is, while stuffed with good content, quite a hard article to chew through. Something a bit lighter would be welcome as an addition. I would recommend that you just publish your article as-is, and insert some links to the relevant sections in peppe's article for those looking for additional detail.

    Anyway, MayaPosch, thanks for publishing this article!



  • Nice read, sharing it. And welcome ^^



  • @Volker I think I agree with Andre on that it'd be better to keep my article as-is so as to keep it very focused on this particular topic (QThread). That way people can click through from peppe's article as said and it wouldn't put my article or peppe's out of context.

    Shall I post this suggestion in the Wiki Discussion forum?

    @Andre Thank you :) I like being passionate about software and good documentation ^_^



  • A note on the contents of the article (I don't feel like creating a Wordpress account to respond there).

    [quote]By the way, one extremely thing to note here is that you should NEVER allocate heap objects (using new) in the constructor of the QObject class as this allocation is then performed on the main thread and not on the new QThread instance, meaning that the newly created object is then owned by the main thread and not the QThread instance.[/quote]
    I think the statement above is false. As long as these objects have the worker object as their parent, they too will be moved to the new thread. From the QObject::moveToThread() documentation (my emphasis):

    [quote]Changes the thread affinity for this object and its children.[/quote]

    Funny enough, this is an issue with the old way of using QThread. People used to create new objects on the heap in their subclasses QThread class constructor, and those would obviously live in the main thread, not in the thread they wanted to start.

    What is noteworthy, but not explicitly mentioned in your article, is that the worker object cannot have a parent, as that would prevent the thread move.



  • [quote author="Andre" date="1330333381"]A note on the contents of the article (I don't feel like creating a Wordpress account to respond there).

    I think the statement above is false. As long as these objects have the worker object as their parent, they too will be moved to the new thread. From the QObject::moveToThread() documentation (my emphasis):

    [quote]Changes the thread affinity for this object and its children.[/quote][/quote]

    Actually, no. I tried it the way you suggested before I wrote the tutorial, but it doesn't work. You do get interesting crashes that way, though, as the heap objects aren't moved :) They remain firmly owned by the main thread. Insert tongue-in-cheek comment here on the accuracy of the Qt documentation ;)

    (Disclaimer: I applied for a job as Qt Technical Writer, but there do not seem to be any open positions ATM :) )

    [quote]What is noteworthy, but not explicitly mentioned in your article, is that the worker object cannot have a parent, as that would prevent the thread move.
    [/quote]

    Well... some things should be obvious, right? I mean... :D



  • [quote author="MayaPosch" date="1330335061"]
    [quote author="Andre" date="1330333381"]A note on the contents of the article (I don't feel like creating a Wordpress account to respond there).

    I think the statement above is false. As long as these objects have the worker object as their parent, they too will be moved to the new thread. From the QObject::moveToThread() documentation (my emphasis):

    [quote]Changes the thread affinity for this object and its children.[/quote][/quote]

    Actually, no. I tried it the way you suggested before I wrote the tutorial, but it doesn't work. You do get interesting crashes that way, though, as the heap objects aren't moved :) They remain firmly owned by the main thread. Insert tongue-in-cheek comment here on the accuracy of the Qt documentation ;)
    [/quote]
    Well, that would warrent a bugreport againt QtCore then. If I look at the sources (I checked 4.7.4) I see that children are moved. If they are not for you, then a bugreport with a sample to reproduce it would be in order.

    [quote]
    (Disclaimer: I applied for a job as Qt Technical Writer, but there do not seem to be any open positions ATM :) )

    [quote]What is noteworthy, but not explicitly mentioned in your article, is that the worker object cannot have a parent, as that would prevent the thread move.
    [/quote]

    Well... some things should be obvious, right? I mean... :D[/quote]
    I don't find it all that obvious, actually, and as you note it complicates the cleanup a bit. Your solution is just one of the ways that can be done, but if you want to recycle your worker objects, you need to come up with a different solution. However, as a basic example yours is a good solution.



  • [quote author="MayaPosch" date="1330332901"]@Volker I think I agree with Andre on that it'd be better to keep my article as-is so as to keep it very focused on this particular topic (QThread). That way people can click through from peppe's article as said and it wouldn't put my article or peppe's out of context.[/quote]

    Thinking about it, this is the better way to go. And it has the additional advantage that we can point users to that page if we need just a short sample of the new usage pattern of QThread :-)



  • Alright, I shall put a new Wiki article together featuring the content of my blog article, then :)



  • http://developer.qt.nokia.com/wiki/QThreads_general_usage

    There you go... feel free to link to it from other articles in an appropriate manner :)

    Feedback is also very welcome.



  • Thank you very much Maya, this tutorial has been very useful for my project!!

    Regards.



  • You're quite welcome, BelenMuñoz :)



  • Thanks for such a nice article, made the picture more clear about the implementation.

    Regards



  • But what about child qobjects (heap objects)?
    By this thread creation method, child objects are not moved in to thread.
    how can i move them into thread?
    please help me.


  • Moderators

    Hi,

    When you move a parent QObject, all its children are automatically moved too.

    Remember though that member variables do not automatically become children; the parent-child relationship must be set by either:

    • passing the parent's pointer into the child's constructor, or
    • calling QObject::setParent()


  • class SecondaryOperation: public QObject
    {
    Q_OBJECT
    private:
    bool printtype;
    QTimer *tt;
    public:
    SecondaryOperation(bool);
    public slots:
    void runsecondaryfunction();
    void ttevent();
    signals:
    void taskfinish();
    };

    i am creating one object of above class in main thread. i am also creating one thread, to which i am passing "runsecondaryfunction()" public slot. in "runsecondaryfunction()" there is one while loop, that will continuous run in thread. i have initialized timer tt in class constructor. timeout event of tt timer is linked with "ttevent()". but there is no timeout event occur. also if i am declaring other seperate timer object in "runsecondaryfunction()", program stop unexpectedly. also i want to use one object of qnetworkaccessmanager in SecondaryOperation class. then how can i use it?


  • Moderators

    Hi jigar.patel,

    There are many parts in your question. Please "start a new discussion":http://qt-project.org/forums/newtopic/10/ and show more of your code (especially the implementation of runsecondaryfunction() and ttevent()) -- your descriptions don't have enough details.

    Also, please put '@' before and after your code to give it proper highlighting. That makes it easier to read.



  • Hello Maya,

    beginner question on this sentence "... you should NEVER allocate heap objects (using new) in the constructor of the QObject class"
    I do not undestand which is the constructor of the QObject class.

    This constructor ? : Worker::Worker() {} ?

    Can i do this way, or is this the constructor meant above ?

    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        ui->setupUi(this);
    
        QThread* thread = new QThread;
        Worker* worker = new Worker();
        worker->moveToThread(thread);
    

    If this is ok ( and it works in this simple version) where not to never allocate ... ?
    thank you


  • Qt Champions 2016

    as far as I can read, she means in the worker constructor as we later do

    Worker* worker = new Worker();
    worker->moveToThread(thread);

    so if we in Worker constructor create new other objects,
    they are not moved and stays in main thread.


  • Moderators

    @mrjj said:

    so if we in Worker constructor create new other objects,
    they are not moved and stays in main thread.

    Only if the other objects aren't parented properly. See the QObject documentation:

    Note: A QObject's member variables do not automatically become its children. The parent-child relationship must be set by either passing a pointer to the child's constructor, or by calling setParent(). Without this step, the object's member variables will remain in the old thread when moveToThread() is called.



  • Hello mrjj,

    if I see this line in the Worker constructor, i tend to assume the code would create a neverending number of Worker objects. For me this looks recursive, (?)
    That's why I asked what Maya meant by NEVER do ... but "what ?"

    Worker::Worker(QObject *parent) : QObject(parent)
    {
    Worker* worker = new Worker();
    ...
    }
    

    In which point my thinking is bad ?


  • Moderators

    @wally123

    Creating an instance of the same object within the constructor is always deadly. That has nothing to do with QThreads.

    @JKSH said:

    Only if the other objects aren't parented properly. See the QObject documentation:

    Note: A QObject's member variables do not automatically become its children. The parent-child relationship must be set by either passing a pointer to the child's constructor, or by calling setParent(). Without this step, the object's member variables will remain in the old thread when moveToThread() is called.

    That is a good point.


  • Qt Champions 2016

    @wally123
    As I read it, she meant other objects

    Worker::Worker(QObject *parent) : QObject(parent)
    {
    SomeWidget*  MyWid= new SomeWidget();
    }
    

    and as JKSH then teach us is that you -can- do that if you then also do

    MyWid->setParent(this)

    I dont think she warned about

    Worker::Worker(QObject *parent) : QObject(parent)
    {
    Worker* worker = new Worker();
    }
    

    And yes, this will be recursive to the point of blowing up.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.