What's the best way to perform this process asynchronously using Qt's threading and concurrency features?
-
I have a dialog window where the user has to enter the URL of an RSS feed. When they click off the text line widget, I want to retrieve the name of the RSS feed from its title attribute. I can do this by querying the feed via the URL. However the library I'm using to do this (feedreaderlib) can sometimes hang when given a URL that's not valid (for example, if I give it a URL to a website that's not a feed, and that site returns malformed HTML).
I need to do two things:
- Perform the query to the RSS feed in a separate thread, so that the dialog doesn't freeze.
- Find a way to detect if the thread's function (namely the call to query the feed) has not returned after say 5 seconds.
What's the best approach to achieve this using Qt?
-
You could use a QTimer in the GUI thread that waits for 5 seconds and then checks whether the query-thread has finished. If your fetching library provides no timeout then you have no choice but to terminate the query thread if it does not finish in time.
-
mkuettler, thanks. What about using a Runnable helper class that get's executed in a thread pool thread, which I set a timeout for to 5 seconds. In that runnable, if it gets past the statement that retrieves the name, it then marshals over to the UI thread by calling this->moveToThread(QApplication::instance()->thread()), and then sets the name value on the QLineEdit widget that was passed in to its ctor?
Seems that approach would achieve the same thing without the threads having to communicate?
-
I think a more elegant solution would be to send a signal in the query thread and connect it to a slot in the GUI thread. When you call this->moveToThread(...) you do move the object, but the following lines of code are still executed in the old thread. When you are in the middle of a function you cannot simply decide to execute the rest of the function in an other thread. Maybe I misunderstood you, but it seemed to me that this is what you where suggesting.
Signals/Slots can cross the thread boundaries, and I recommend using them for that, because they take care of all the communication/concurrency issues. -
mkuettler, yes I was under the mistaken impression that Qt would marshal the remaining code in that function to the other thread, but I guess that magic isn't provided for so as you say, the remaining execution would be on the old thread. So out of curiosity, after calling moveToThread, at what point do future operations execute on the new thread? Or is that not really what it's doing?
I will look at a signal and slots solution, sounds like the better approach.
-
[quote author="Little Red Wolf" date="1340101173"]So out of curiosity, after calling moveToThread, at what point do future operations execute on the new thread? Or is that not really what it's doing?[/quote]
The eventloop will run in the new thread, so all event handlers and slots that where connected with some kind of queued connection (the default connection mode does that for slots in different threads) will be executed in the new thread. Everything else is what you call directly, which will obviously be executed in the thread of the caller.
-
So mkuettler, doesn't that imply that using slots for my needs still requires me to move the object back to the Application's thread?
-
-
I see so the slot always executes in the thread of the object that the slot is defined on?
-
[quote author="Little Red Wolf" date="1340138548"]I see so the slot always executes in the thread of the object that the slot is defined on?[/quote]
Yes, that is what I meant to write. Reading it again I must admit that that isn't quite clear from what I wrote.
-
Ok, I have this all wired up but as I mentioned I'm using the thread pool, so my class is a QRunnable. However in order to have signals, it needs to also inherit from QObject. Fine, compiles, links, great. But when I call QThreadPool::getGlobalInstance()->start(myRunnable), the run() method on my runnable never gets called. Can't see why. Any ideas?
-
I'm not sure what the problem is. But if you have other QRunnables already running in the QThreadPool it could be that maxThreadCount() threads are already running, and the new thread is just appended to the ready queue, waiting for one of the other threads to terminate.
-
mkuettler, I have no other runnables, it's the only one. My runnable also inherits from QObject in order to support signals, could that be a problem? How does one go about debugging this?
-
I find it very hard to guess what the problem might be, as my knowledge about threads is very limited. Could you maybe post some of your code here?
You might also want to read "Threads, Events and QObjects":http://qt-project.org/wiki/Threads_Events_QObjects. I havn't read it myself yet, but it seems to be a good read on that topic.
-
Another good read on threads and the recommended approach for using QThreads is "this one":http://qt-project.org/wiki/QThreads_general_usage.