Реализовать точный таймер в Qt


Поскольку мне нужен более точный таймер, чем Qt с его разрешением ~15 мс, я попытался реализовать свой собственный таймер с помощью QueryPerformanceCounter () из api windows.

Мой первый шаг состоял в том, чтобы унаследовать от QObject и построить таймер с бесконечным циклом, который запускает сигнал каждую секунду. Я попытался переместить этот таймер в его собственный поток с помощью moveToThread (), чтобы он просто обновлял мое главное окно каждую секунду и не блокировал все это. Однако главное окно никогда не появится, удаление бесконечного цикла - > появляется главное окно.

Итак, я попробовал подход с одной точкой зрения, основная идея такова:

 connect( highPerformanceTimer, SIGNAL(timer_tick()), this, SLOT(timeOutSlot()) );
 connect( this,  SIGNAL(graphics_updated()), highPerformanceTimer, SLOT(timer_start()));

Итак, таймер тикает, пользовательский интерфейс (opengl) обновляется, в конце обновления генерируется сигнал для перезапуска таймера.

Тем не менее мое главное окно не будет отображаться до тех пор, пока я не удалю перезапуск таймера из конца кода обновления пользовательского интерфейса.

В отладчике я вижу, что код, кажется, работает так, как должен, он переходит от таймера к пользовательскому интерфейсу и назад. Без точек останова это приведет к внезапному сбою сегментации.

Я был бы благодарен за любую подсказку, где может быть проблема или есть ли лучший способ реализовать это в Qt.

Правка: еще немного кода

Highperformance Timer.h

#ifndef HIGHPERFORMANCETIMER_H
#define HIGHPERFORMANCETIMER_H

#include <QObject>
#include <windows.h>

class HighPerformanceTimer : public QObject
{
    Q_OBJECT
public:
    HighPerformanceTimer();

signals:
    void timer_tick();

public slots:
    void timer_start();

private:
    // some variables
    LARGE_INTEGER highPerformanceCounterValue, highPerformanceCounterFrequency, highPerformanceCounterValueOld;
    int interval;
    float value;
    float last_tick_value;

};

#endif // HIGHPERFORMANCETIMER_H

Highperformance Timer.cpp

#include "highperformancetimer.h"
#include "windows.h"
#include "QThread"


HighPerformanceTimer::HighPerformanceTimer()
{

    QueryPerformanceFrequency(&highPerformanceCounterFrequency);
}



void HighPerformanceTimer::timer_start(){
    float i = 0;
// just burn some time
    while( i<1000000 ) i++;
    emit HighPerformanceTimer::timer_tick();   
}

Некоторый код из основного виджета OpenGl:

HighPerformanceTimer *highPerformanceTimer;
protected slots:
    virtual void timeOutSlot();

NeHeChapter5( QWidget *parent=0, char *name=0 ) : NeHeWidget( 50, parent, name )
    {
        highPerformanceTimer = new HighPerformanceTimer();

        connect( highPerformanceTimer, SIGNAL(timer_tick()), this, SLOT(timeOutSlot()) );
        connect( this,  SIGNAL(graphics_updated()), highPerformanceTimer, SLOT(timer_start()));
        highPerformanceTimer->moveToThread(&timerThread);
        highPerformanceTimer->timer_start();
    }

void NeHeChapter5::timeOutSlot(){
    timeOut();
}

void NeHeChapter5::timeOut()
{
    updateGL();
}

void NeHeChapter5::paintGL()
{
//opengl code *snip*
emit graphics_updated();
}
1 3

1 ответ:

Ошибка здесь:

NeHeChapter5( QWidget *parent=0, char *name=0 ) : NeHeWidget( 50, parent, name )
{
    highPerformanceTimer = new HighPerformanceTimer();

    connect( highPerformanceTimer, SIGNAL(timer_tick()), this, SLOT(timeOutSlot()) );
    connect( this,  SIGNAL(graphics_updated()), highPerformanceTimer, SLOT(timer_start()));
    highPerformanceTimer->moveToThread(&timerThread);
    highPerformanceTimer->timer_start();
}

Вы вызываете timer_start(); и он вызывается в вызывающем потоке, а не в timerThread. Кроме того, вы даже не начали свою нить. Сначала позвоните timerThread.start(). Чтобы вызвать timer_start () в потоке, который вы хотите, вы должны вызвать

QMetaObject::invokeMethod(highPerformanceTimer, "timer_start", Qt::QueuedConnection);

Он вызовет timer_start во вновь запущенном потоке, а не в вызывающем потоке.

Также вам не нужно вызывать timer_tick с полным именем emit HighPerformanceTimer::timer_tick(); можно заменить на emit timer_tick();