I want use qthread do a ping job and sleep with specified time,but sometimes the thread sleep time is wrong,I tried on Qt5.6.3 and 5.9.3,both not work.
here is my demo code:
#include "mainwindow.h"
#include <QApplication>
#include <QThread>
#include <QDebug>
#include <QDateTime>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
MainWindow w;
w.show();
QThread *thread = new QThread;
QObject::connect(thread,&QThread::started,[=]{
while(true){
QDateTime dateTime = QDateTime::currentDateTime();
qDebug() << dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz") << "start..." ;
QThread::msleep(7000);
}
});
thread->start();
return a.exec();
}
but but but the console output is:
"2018-06-01 17:40:22.603" start...
"2018-06-01 17:40:29.608" start...
"2018-06-01 17:40:36.612" start...
"2018-06-01 17:40:43.613" start...
"2018-06-01 17:40:50.618" start...
"2018-06-01 17:40:57.623" start...
"2018-06-01 17:41:04.628" start...
"2018-06-01 17:41:11.629" start...
"2018-06-01 17:41:18.633" start...
"2018-06-01 17:41:25.634" start...
"2018-06-01 17:41:32.639" start...
"2018-06-01 17:41:39.640" start...
"2018-06-01 17:41:46.645" start...
"2018-06-01 17:41:53.650" start...
"2018-06-01 17:42:00.655" start...
"2018-06-01 17:42:07.659" start...
"2018-06-01 17:42:14.661" start...
"2018-06-01 17:42:21.666" start...
"2018-06-01 17:42:28.670" start...
"2018-06-01 17:42:35.674" start...
"2018-06-01 17:42:42.674" start...
"2018-06-01 17:42:59.673" start... "2018-06-01 17:43:16.398" start...
"2018-06-01 17:43:23.399" start...
"2018-06-01 17:43:40.399" start...
"2018-06-01 17:43:50.297" start...
"2018-06-01 17:43:57.297" start...
"2018-06-01 17:44:14.297" start...
"2018-06-01 17:44:31.297" start...
"2018-06-01 17:44:48.296" start...
"2018-06-01 17:45:05.296" start...
"2018-06-01 17:45:22.296" start...
"2018-06-01 17:45:31.299" start...
"2018-06-01 17:45:48.299" start...
"2018-06-01 17:46:04.806" start...
I marked the error line,someone know why???? Thanks
That's entirely within the tolerances of your approach. You're not running some sort of a realtime control system. You're running it on a desktop platform. Such timing accuracy is expected.
But you're of course doing it wrong too, since such sleeping will always accumulate positive timing drift. The drift gets worse as you do more work between the sleep calls: the sleep assumes that you never overslept, and that the I/O code takes zero time. That's of course a wrong assumption. System timers compensate for that.
At the very least, ensure that your sleep compensates any slips (mode = CompensatedSleep
), or ideally use the timer (mode = Timer
). The example below illustrates all three approaches, including your original one (mode = DriftySleep
).
// https://github.com/KubaO/stackoverflown/tree/master/questions/timer-modes-50640879
#include <QtWidgets>
struct Thread final : QThread {
~Thread() override { finish(); wait(); }
void finish() { quit(); requestInterruption(); }
};
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
QPushButton toggle{"Click to Stop"};
toggle.setMinimumSize(300, 150);
toggle.show();
Thread thread;
QTimer timer;
QObject::connect(&toggle, &QPushButton::clicked, [&]{
thread.finish();
toggle.setDisabled(true);
});
QObject::connect(&thread, &Thread::finished, &toggle, &QWidget::close);
constexpr enum { DriftySleep, CompensatedSleep, Timer } mode = CompensatedSleep;
qint64 constexpr setPeriod = 7000;
auto dump = [period = Q_INT64_C(0), watch = QElapsedTimer()](qint64 load = {}) mutable {
qint64 current = watch.isValid() ? watch.elapsed() : 0;
auto dateTime = QDateTime::currentDateTime();
qDebug() << dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz") << current;
if (!watch.isValid()) {
watch.start();
period = load;
} else
period = watch.restart();
return period;
};
if (mode != Timer) QObject::connect(&thread, &Thread::started, [&]{
auto period = dump(setPeriod);
while (!thread.isInterruptionRequested()) {
QThread::msleep(setPeriod*2 - ((mode == CompensatedSleep) ? period : setPeriod));
period = dump();
}
});
else {
timer.setTimerType(Qt::PreciseTimer);
timer.start(setPeriod);
timer.moveToThread(&thread);
QObject::connect(&thread, &Thread::finished, [&]{ timer.moveToThread(thread.thread()); });
QObject::connect(&thread, &Thread::started, [&]{ dump(setPeriod); });
QObject::connect(&timer, &QTimer::timeout, [&]{ dump(); });
}
thread.start();
return app.exec();
}