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- App starts and start single thread , also see signal/slot connect between the thread object and the main app
- Thread gets data from remote server as xml format its and sets the data into object container (class that represent the data )
- when the data is ready in the object it trigger SIGNAL back to the main app (the signal/slot from section 1)
- 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 .
-
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 ?
-
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.
-
[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_OBJECTpublic slots:
void doWork() {
/* ... */
}
};/* ... */
QThread *thread = new QThread;
Worker *worker = new Worker;
connect(obj, SIGNAL(workReady()), worker, SLOT(doWork()));
worker->moveToThread(thread);
thread->start();
@ -
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 herem_Thread.start() }
@