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 longdoSomething()
takes and sleep that much shorter than 1000ms.Both
doSomething()
andmsleep()
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 ofdoSomething()
.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();
}