I have written a thread in Qt that does lot of things (calculations, data sampling, ...).
This thread has to be run in an interval of 1000ms.
The allowed error with the timer is about 5ms.
I have changed the priority of the thread to QThread::HighPriority but the thread runs in interval about to 1060ms-1100ms.
How can I make the interval more precise? (I have subclassed QThread and used msleep(interval) in the run() method).
You have coded your thread's run() method essentially as:
void MyThread::run() {
forever {
doSomething();
msleep(1000);
}
}
There are several problems:
doSomething() doesn't take zero amount of time. At the minimum, you'd need to time how long doSomething() takes and sleep that much shorter than 1000ms.
Both doSomething() and msleep() can take a variable amount of time, since your thread is never guaranteed not to be preempted, nor is it guaranteed to immediately start running once it's made runnable by the sleep expiring. Thus you need to keep track of time absolutely, not relatively to the start of doSomething().
You're using a generic sleep function without possibly leveraging better APIs that the underlying platform might offer.
A reasonably correct way to go about it would be expressed using this pseudocode:
const qint64 kInterval = 1000;
qint64 mtime = QDateTime::currentMSecsSinceEpoch();
forever {
doSomething();
mtime += kInterval;
qint64 sleepFor = mtime - QDateTime::currentMSecsSinceEpoch();
if (sleepFor < 0) {
// We got preempted for too long - for all we know, the system could
// have even gotten suspended (lid close on a laptop).
// Note: We should avoid the implementation-defined behavior of
// modulus (%) for negative values.
sleepFor = kInterval - ((-sleepFor) % kInterval);
}
OS_Precise_Wait_ms(sleepFor); // use the appropriate API on given platform
}
As luck would have it, Qt provides an API that does all this for you: the timers. They are a source of reasonably behaved periodic "ticks". Most naive re-implementations of this functionality are likely to get it wrong in one way or another, since it's not as simple as it looks.
Here is how you can reorganize the code:
class Worker : public QObject {
QBasicTimer m_timer;
void doSomething() {
// do the work
}
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() != m_timer.timerId()) {
QObject::timerEvent(ev);
return;
}
doSomething();
}
public:
Worker(QObject * parent = 0) : QObject(parent) {
m_timer.start(1000, Qt::PreciseTimer, this);
}
};
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
Worker worker;
QThread workerThread;
worker.moveToThread(workerThread);
workerThread.start(QThread::HighPriority);
// Example of how to terminate the application after 10 seconds
// Requires Qt 5 and a C++11 compiler.
QTimer timer;
QObject::connect(&timer, &QTimer::timeout, [&](){
workerThread.quit();
workerThread.wait();
app.quit();
});
timer.setTimerType(Qt::VeryCoarseTimer);
timer.setSingleShot(true);
timer.start(10000);
return app.exec();
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With