Persistent threading with Qt
-
I need to make some persistent threads. By this I mean that I would like them to live for the duration of the application. For the sake of brevity, lets pretend that I need two worker threads. The threads will be fed continuously throughout the life of the application. I need to know in an efficient way when the two threads are both finished the current work assigned to them, so that I can assign them new work.
At the following "link":http://doc.qt.nokia.com/4.7-snapshot/thread-basics.html#example-1-using-the-thread-pool it is suggested that if one wants persistent threads (that don't die when their run function completes), that we should do threading as follows:
@
class Worker : public QObject
{
Q_OBJECTpublic slots:
void doWork() {
/* ... */
}
};QThread *threadA = new QThread;
QThread *threadB = new QThread;
Worker *workerA = new Worker;
Worker *workerB = new Worker;
workerA->moveToThread(threadA);
workerB->moveToThread(threadB);
threadA->start();
threadB->start();
QMetaObject::invokeMethod(workerA, "doWork", Qt::QueuedConnection);
QMetaObject::invokeMethod(workerB, "doWork", Qt::QueuedConnection);@My problem with this approach is that we cannot use the QThread::wait() function because that only works when you use the scheme where you implement run(). This leaves me with no way to know when the threads have finished their work. Instead this only tells me when the threads have been exited. If I use some flags that the threads manipulate, then I'm left in a situation where I have to poll constantly checking those flags, which steals cpu time from the workers. We need a mechanism where the caller that feeds the threads waits until the threads are ready to be fed more work, but no longer. If there was a way to use signals to reflect thread work completion I would still be in trouble because that still leaves the caller needing to be suspended and then woken up, but signals cannot wake up the caller which initiated everything to begin with. As far as I know, a signal can only call a function. It cannot unfreeze an already executing function that is waiting for some event.
The docs state that if we want to not kill the threads when they have finished some work that they can be kept in a pool and wait to be used again later. Code sample below:
@
class Work : public QRunnable
{
public:
void run()
{
qDebug() << "Hello from thread " << QThread::currentThread();
}
};int main(int argc, char *argv[])
{
QCoreApplication app(argc, argv);
Work workA;
Work workB;
workA.setAutoDelete(false);
workB.setAutoDelete(false);
QThreadPool *threadPool = QThreadPool::globalInstance();//first chunk of work threadPool->start(&workA); threadPool->start(&workB); threadPool->waitForDone(); //doesn't this remove the threads from the thread pool? //second chunk of work threadPool->start(&workA); threadPool->start(&workB); threadPool->waitForDone(); return 0;
}@
The docs contradict this statement in the same document because they categorize the QThreadpool implementation as a "one call" thread life scheme. Also the docs say that when you call waitForDone(), that "Waits for each thread to exit and removes all threads from the thread pool." If the threads are removed from the thread pool then obviously this thread pool scheme cannot be used to recycle threads.
Any clarifications would be greatly appreciated.
-
I am confused ;-)
Your first sentence is:
bq. I need to make some persistent threads.
So, IMO, Method1 should work for you.
But, then, you complain that
bq. My problem with this approach is that we cannot use the QThread::wait() function because that only works when you use the scheme where you implement run(). This leaves me with no way to know when the threads have finished.
-
Why you want "persistent threads" finished?
-
QThread::wait() should works well.
-
If you want to exit one thread,
@
thread->exit();
thread->wait();
@ -
If you want to get a signals just when your doWork() finished, you should add a signal to you class, then emit it before doWork() finished.
-
-
- You trimmed my quote. I didn't say finished... I said finished their work. By finished I don't mean I want to know when the threads have quit() or exit(), instead I need to know when the persistent threads have finished doing the work that I assigned to them(when the function I told them to work on has finished its work) so that I can assign more work to the threads. That is the whole point of persistent threads... instead of terminating them... you keep feeding them with more work.
- Maybe QThread:wait() "should" work but it doesn't! When you implement run() then QThread::wait() returns on 3 conditions. One, run is done. Two, thread has quit() or exit(). Three, timer runs out. When you do threading as shown above then wait() only works with conditions two and three. Thus, there is no way to know when run() has finished its work because there is no run(). As such, in such a scenario QThread::wait() only tells us when the thread has terminated and since we are dealing with persistent threads this is useless info because that will be at the end of program.
- I don't want to exit threads. I want to keep the threads alive and keep feeding them more work.
- Signals don't work for the scenario described in the original post.
@
//Imagine an outside force like an OS/driver using using a callback function.
infinite loop by external force
{
//Gets called a lot so want to re-use threads instead of creating new threads each time.
C callback function(some parameters)
{
//Have threads help with processing work in this function that is computational expensive.
Gives some existing pre-made threads some work to do and wait for threads to finish
work (do not terminate threads because they will be re-used next time C callback function is called).Do some more work in here after current computation by threads are complete. }
}@
So, the callback is like a driver. It gets called by outside user I can't influence. Need some way to pause execution of C callback function while threads finish work. Don't confuse this with threads finishing in the sense that they are terminated. As soon as the threads finish work, the call back should resume with its remaining work. Then...when the callback is called again I want to feed the same existing threads with new work. I don't want to create new threads in the callback function because creating threads is expensive. Threads are made at start of app and terminated at end of app. I don't see how a signal will solve the issue at all. A signal can only call some function. That is not what I need. I need a way to pause execution of a running function (the callback function) and to resume execution of the function when threads have done their work.
The main problem is that there is no way to block in the callback function until threads are done working. QThread::wait() when working with persistent threads as shown in original post only unblocks when thread die or timer runs out. This is useless. I could run a busy loop checking some flags but that is not efficient and steals CPU time from worker threads.
-
From QThreadPool docs i see:
Threads that are unused for expiryTimeout milliseconds are considered to have expired and will exit. Such threads will be restarted as needed. The default expiryTimeout is 30000 milliseconds (30 seconds). If expiryTimeout is negative, newly created threads will not expire, e.g., they will not exit until the thread pool is destroyed.Which means you can really make them persistent as you desire. "Quote sorce":http://qt-project.org/doc/qt-4.8/qthreadpool.html#expiryTimeout-prop
-
-
You seems mis-understand the function of QThread::run(), QThead::wait(), QThread::exec(), QThread::quit(), QThread::exit(), ...
-
quit(), exit() only works when a eventloop is running in the thread. If you re-implement the QThread::run(), and QThread::exec() is not called in this function, quit() and exit() do nothing.
-
Once QThread::run() finished, the Thread finished! QThead::wait() only returned when the thread finished.
-
As I have said before, if you don't want to exit the thread, an want to using signal and slots, Method1 is designed for you.
-
-
At to point number 4, the problem with Method 1 is that there is no efficient way to block the caller until all the threads have completed a currently assigned chunk(round) of work. I'll highlight this sample of pseudo code again to illustrate the problem.
@ //Imagine an outside force like an OS/driver using using a callback function.
infinite loop by external force
{
//Gets called a lot so want to re-use threads instead of creating new threads each time.
C callback function(some parameters)
{
//STEP 1
//Feed 2 threads with computational expensive work.
//threads should be pre-made threads to save time on thread creation.
//do not terminate threads because they will be re-used next time C callback
//function
//is called with a new round of work.//STEP 2 //Need to pause/wait/BLOCK function execution here until the 2 worker threads //have completed the work. //THIS IS THE PROBLEM! No efficient way to block! I don't see how a signal/slot //can be used for this purpose. //STEP3 //After 2 threads complete their assigned work, resume execution of this C //callback function. //Perform some non-threaded work in this function to complete the job. //return (end function execution), all work for this round/call is complete. } }@
The problem with Method 1 is that there is no way to block as explained in the above pseudo code. If you know of an efficient way, please show me how. I think if you think through the signal slot thing you will see that they can't be used for blocking. This leads back to what I started with in this post, there doesn't seem to be a efficient way in Qt to know when persistent threads have completed a round of work. I can only know this by checking some flags in a while loop repeatedly which steels CPU time away from the threads.
As for Method 2, using a QThreadPool, if as in the code sample at the top of the post, if threadPool->waitForDone(); is used for BLOCKING, the docs say that
waitForDone() removes all threads from the thread pool!
That means...provided that the docs are not in error, that threadPool->waitForDone() can no be used if the goal is a persistent threading scheme. Leaving me with once again no efficient way to BLOCK until the threads have completed a round of work. -
Several questions:
- Why there this a infinite loop? In which thread it is running? Does this thread have a eventloop?
@
//Imagine an outside force like an OS/driver using using a callback function.
infinite loop by external force
{
@
If this thread does not have a eventloop, it can not a UI thread, you can using QMutex, QWaitCondition, ....
If this thread does have a eventloop, this inifinite can be removed, signals and slots will work across threads.
- ThreadPool is designed for this.
@
//STEP 1
//Feed 2 threads with computational expensive work.
//threads should be pre-made threads to save time on thread creation.
//do not terminate threads because they will be re-used next time C callback
@
Again, you should use QMutex, QWaitCondition, ....
Though they works with ThreadPool, but ThreadPool and Runable does not designed for this case.
@
//STEP 2
//Need to pause/wait/BLOCK function execution here until the 2 worker threads
//have completed the work.
@- Yes, this is true. you want the threadPool finished. and when the pool finished, it will delete all the QThreads which are managed by the pool.
@
As for Method 2, using a QThreadPool, if as in the code sample at the top of the post, if threadPool->waitForDone(); is used for BLOCKING, the docs say that
waitForDone() removes all threads from the thread pool!
@
- Why there this a infinite loop? In which thread it is running? Does this thread have a eventloop?
-
-
The operating system is calling my c function. Very often.
-
I DO NOT want the thread pool to delete any threads when the work is finished.
I don't see how QMutex or QWaitCondition can be used for blocking until threads have completed the current work assigned to them for the current C_Callback)function call. if you think this can be done, I'd like to see some code to demonstrate this. The devil is in the details...
-