Vincent Göbel
Vincent Göbel

Reputation: 33

Implement precise timer in Qt

Since I need a more precise timer than the Qt one with its ~15ms resolution i tried to implement my own timer using QueryPerformanceCounter() from the windows api.

My first shot was to inherit from QObject and build a timer with an infinite loop that fires a signal every second. I tried to move this timer to its own thread with moveToThread() so that it would just update my main window every second and not block the whole thing. However the main window would never show up, removing the infinite loop -> main window shows up.

So I tried a singleshot approach, the basic idea is:

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

So, timer ticks, ui (opengl) gets updated, at the end of the update a signal is generated to restart the timer.

Still my main window will not show up as long as i don't remove the restart of the timer from the end of the ui update code.

In the debugger I can see that the code seems to work like it should, it jumps from timer to ui and back. Without breakpoints it will result in a sudden segmentation fault.

I would be thankful for any hint where the problem could be or if there is a better way to implement this in Qt.

Edit: Some more code

highperformancetimer.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

highperformancetimer.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();   
}

Some Code from the main OpenGl Widget:

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();
}

Upvotes: 3

Views: 2230

Answers (1)

Kamil Klimek
Kamil Klimek

Reputation: 13130

Error is here:

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();
}

You call timer_start(); and it's being called in caller thread, not in timerThread. Also you didn't even start your thread. Call timerThread.start() first. To invoke your timer_start() in thread you want you should call

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

It will invoke timer_start in newly started thread, not in caller thread.

Also you don't need to call timer_tick with fully qualified name emit HighPerformanceTimer::timer_tick(); can be replaced with emit timer_tick();

Upvotes: 1

Related Questions