QThread中的精确间隔

混日子

我在Qt中编写了一个线程,该线程可以执行很多操作(计算,数据采样等)。
该线程必须以1000ms的间隔运行。
计时器的允许错误约为5毫秒。
我已将线程的优先级更改为,QThread::HighPriority但线程的运行间隔大约为1060ms-1100ms。
如何使间隔更精确?(我将QThread子类化,并msleep(interval)在该run()方法中使用)。

库巴并没有忘记莫妮卡

run()基本上将线程的方法编码为:

void MyThread::run() {
  forever {
    doSomething();
    msleep(1000);
  }
}

有几个问题:

  1. doSomething()不会花费零时间。至少,您需要计时需要多长时间doSomething(),并且睡眠时间要短于1000毫秒。

  2. 双方doSomething() msleep()可以采取可变的时间量,因为你的线程永远不能保证被抢占,也不是保证立即开始,一旦它也会因为睡眠到期可运行的运行。因此,您需要绝对跟踪时间,而不是相对于的开始doSomething()

  3. 您正在使用通用的睡眠功能,而没有可能利用基础平台可能提供的更好的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();
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章