我想使用qthread执行ping作业并在指定时间内休眠,但有时线程睡眠时间错误,我试过Qt5.6.3和5.9.3,两者都不起作用。
这是我的演示代码:
#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();
}
但是但是控制台输出是:
"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...
我标记了错误行,有人知道为什么???? 感谢
答案 0 :(得分:0)
QThread没有任何问题,也没有自我保护。它们根本不是为此任务而设计的。
macOS 不是一个实时操作系统,因此一旦你将一个线程置于睡眠状态,就绝对无法保证它会在一段精确的时间后唤醒。它将尽力而为,但无论出于何种原因,它可能需要更长/更短的时间。
如果您需要精确计时,可以使用 Qtimer 与 Qt :: PreciseTimer (文档here)。
举个例子:
QTimer *timer = new QTimer(this);
timer->setTimerType(Qt::PreciseTimer)
timer->setInterval(7000);
connect(timer, &QTimer::timeout(), this, []{
QDateTime dateTime = QDateTime::currentDateTime();
qDebug() << dateTime.toString("yyyy-MM-dd hh:mm:ss.zzz") << "start..." ;
});
timer->start();
答案 1 :(得分:0)
这完全在您的方法的容差范围内。你没有运行某种实时控制系统。您正在桌面平台上运行它。这种计时准确性是预期的。
但你当然也做错了,因为这样的睡眠总会积累正时间漂移。当你在睡眠调用之间做更多的工作时,漂移会变得更糟:睡眠假设你从不睡过头,而I / O代码则需要零时间。这当然是一个错误的假设。系统计时器可以弥补这一点。
至少,确保您的睡眠补偿任何单据(mode = CompensatedSleep
),或理想情况下使用计时器(mode = Timer
)。下面的示例说明了所有三种方法,包括原始方法(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();
}