我在Qt写了一个很多东西(计算,数据采样......)
该线程必须以1000毫秒的间隔运行
计时器允许的错误大约是5毫秒
我已将线程的优先级更改为QThread::HighPriority
,但线程在大约1060ms-1100ms的间隔内运行。
如何使间隔更精确? (我已将QThread子类化,并在msleep(interval)
方法中使用run()
。
答案 0 :(得分:8)
您已将线程的run()
方法编码为:
void MyThread::run() {
forever {
doSomething();
msleep(1000);
}
}
有几个问题:
doSomething()
不会花费任何时间。至少,您需要计算doSomething()
花费的时间和睡眠时间超过1000毫秒。
doSomething()
和 msleep()
都可能花费不定的时间,因为您的线程永远不会被保留,也不会立即被保证一旦睡眠到期,它就可以开始运行。因此,您需要绝对跟踪时间,而不是相对于doSomething()
的开头。
您正在使用通用睡眠功能,而无需利用底层平台可能提供的更好的API。
使用此伪代码表示一个合理正确的方法:
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
}
幸运的是,Qt提供了一个API,可以为您完成所有这些:定时器。它们是合理表现的周期性“滴答声”的来源。大多数天真的重新实现此功能可能会以某种方式弄错,因为它并不像它看起来那么简单。
以下是重新组织代码的方法:
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();
}
答案 1 :(得分:1)
来自 QTimer 类的文档:
准确度和计时器分辨率
计时器的准确性取决于底层操作系统和 硬件。但是,大多数平台支持1毫秒的分辨率 定时器的精度在很多方面都不等于这个分辨率 现实世界的情况。
准确度还取决于计时器类型。对于 Qt :: PreciseTimer , QTimer将尝试将精度保持在1毫秒。精确的计时器 也永远不会超出预期的时间。
对于 Qt :: CoarseTimer 和 Qt :: VeryCoarseTimer 类型,QTimer可能会唤醒 早于预期,在这些类型的利润率:5%的 Qt :: CoarseTimer的间隔和Qt :: VeryCoarseTimer的500 ms。
如果系统繁忙,所有计时器类型可能会超出预期的时间 或无法提供所要求的准确性。在这种超时的情况下 溢出,即使多次超时,Qt也只会发出一次activate() 已经过期,然后将恢复原来的间隔。