How to update main windows from running thread , the right way



  • Hello
    I have simple application that in the main view I have QListview . my flow going like this I need to know if it right

    1. App starts and start single thread , also see signal/slot connect between the thread object and the main app
    2. Thread gets data from remote server as xml format its and sets the data into object container (class that represent the data )
    3. when the data is ready in the object it trigger SIGNAL back to the main app (the signal/slot from section 1)
    4. The SIGNAL invoking update function that sets the formatted data into the QListView via its model (QAbstractListModel)

    The problem is when stage 4 is happening I see some freeze in the application for 2-3 seconds that makes me wonder what is wrong here .



  • Sounds correct to me. Is it possible that during 4 the main thread is busy doing some sort of validation or computation?



  • I think im going to check it with "http://www.codersnotes.com/sleepy/":http://www.codersnotes.com/sleepy/
    first then will come back and tell here



  • after profiling the app with sleepy it looks like the delay in the app im not sure but is shows in the Exclusive column very high number 322.35s. in my Thread that calls the http request inside the run method i have this code that cause the thread to pause.

    @void RequestThread::run()
    {
    m_RequestThreadTimer = new QTimer();
    connect(m_RequestThreadTimer, SIGNAL(timeout()),
    this,SLOT(fire(),Qt::DirectConnection));
    QVariant val(GetValFromConfig());
    int interval = val.toInt();
    m_RequestThreadTimer->setInterval(interval);
    m_RequestThreadTimer->start();
    QThread::exec();
    }
    @

    but now is the question how to improve it ?



  • Im not sure but mb for first in the method GetValFromConfig() u use some another method from object that was created in main thread. And second, i think that directconnection is not need in this case.



  • Well, on that last one, I tend to disagree. The problem is that the slot is defined on the QThread subclass. That is not the recommended way to work with threads. The QThread object itself is in the main thread (and please, don't move the QThread object to the thread itself...). The timer is in the RequestThread however. When the timer fires, the current thread will be the RequestThread. Because the fire() slot is defined on the RequestThread object that lives in the main thread, a queued connection will be used. That is not what umen242 is after, I think. So, a direct connection is on order if you want to use this setup.

    A better way to do this would probably be to create a QObject-derived worker class. Create an instance of that class, create a vanilla QThread instance, and move the worker object to the thread of that QThread object and start the thread. There is no need to subclass QThread, and it usually doesn't do what you expect it to do anyway.



  • GetValFromConfig() is from singleton object that holds the app config does it matter ?
    directconnection is there because i saw recommendations in the net to stick it there



  • Thanks Andre for your very informative answer but i must admit , you confused me here ,
    can you direct me to link that shows me some code , how it suppose to look ?
    Thanks



  • [quote author="umen242" date="1325148899"]Thanks Andre for your very informative answer but i must admit , you confused me here ,
    can you direct me to link that shows me some code , how it suppose to look ?
    Thanks[/quote]

    Yeah, sorry, it is a bit confusing.
    "This wiki article":http://developer.qt.nokia.com/wiki/ThreadsEventsQObjects has a lot of detail on this topic. The code below is lifted from this article:

    @
    class Worker : public QObject
    {
    Q_OBJECT

    public slots:
    void doWork() {
    /* ... */
    }
    };

    /* ... */
    QThread *thread = new QThread;
    Worker *worker = new Worker;
    connect(obj, SIGNAL(workReady()), worker, SLOT(doWork()));
    worker->moveToThread(thread);
    thread->start();
    @



  • Thanks again, im reading the wiki you posted , after implementing this method of thread creation
    do you think i can still use the pause timer i used in the original thread ?



  • Of course you can! Just create your timer in the worker class itself, and replace the doWork() slot with something that starts that timer.



  • i finished to read it , one small thing i didn't understand or didn't noticed what is the "obj" in the :
    @connect(obj, SIGNAL(workReady()), worker, SLOT(doWork()));@
    you have idea?



  • It is an object living in the main thread that signals that there is work to be done for the thread.



  • Hmm in my case is , i need the thread start when some object is initialized , so i guess i can remove it
    but when i think about it , what will trigger the DoWork() method ?
    for example:
    i have this object and method ApiManager->Init() that inside the Init() i want to start the thread to work so this is what is did :
    @//Singeltone object
    ApiManager::ApiManager()
    {
    m_Thread = new QThread();
    m_Worker = new Worker() // is the same as in the wiki example
    m_Worker->moveToThread(m_Thread);
    }

    ApiManager::Init()
    {
    m_Thread->start();
    }@

    what will trigger me the DoWork here ? or any other method inside the thread ?
    i dont need here another mechanize to trigger the signal inside the worker . it needs to start when the thread start.



  • So... why don't you connect the thread's started() signal with the doWork() slot? That way, your worker will start to do it's job as soon as the thread starts.

    However, note that this setup is most useful for situations where the worker can get more than one request to do some piece of work. If you 'just' need a one-of operation to run in a thread, then you probably are better off using a QRunnable or subclassing QThread and reimplementing the run() method (without using slots on the subclassed QThread, of course).



  • ok so this is what was my initial setup to start the thread i subclass he thread and invoke the QThread start() and the start trigger the QThread::run()
    and inside the run i have the code that i show above that cause the problem .
    so what do you think is the best solution here ? maybe the timer code is wrong after all .

    like this :
    @ //Singeltone object
    ApiManager::ApiManager()
    {
    // im not using new QThead here

       m_Thread.start()
    
    }
    

    @



  • Some update ,
    after implementing the thread as worker object , i eliminated the delay in my gui , now its just works
    smooth.
    thanks andre !


Log in to reply
 

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