QTimer Hintergrundinformationen

Alles rund um die Programmierung mit Qt
Antworten
sacrif
Beiträge: 40
Registriert: 22. Januar 2010 18:52

QTimer Hintergrundinformationen

Beitrag von sacrif »

Hi,

Kann mir jemand genauer erklären, was im Hintergrund passiert, wenn mittels QTimer in regelmässigen abständen eine Funktion aufgerufen wird. Also wenn ich zb 2 ms einstelle. Was passiert in der Zwischenzeit - wird hier daweil der Thread/Prozess gewechselt oder nur im bestehenden Prozess/Thread abgewartet? Und was ist der Unterschied zum Aufruf von Sleep() oder Yield() (abgesehen natürlich jetzt davon dass durch Sleep()/Yield() keine Funktion aufgerufen wird). Ich meine hier wirklich was im Hintergrund passiert.


Zur genaueren Erklährung meines Problems:

Ich habe ein Programm in dem gleichzeitig (ein nicht von mir geschriebener) renderer verwendet wird. Dabei übergebe ich dem renderer gewisse Daten, er erstellt ein Bild dass ich wiederum auslesen kann.

Genauer will ich eine Reihe von Daten übergeben und ein Bild nach dem anderen auslesen. Das Problem dabei: der Renderer lauft auf der Grafikkarte und braucht immer ein Zeitchen bis dass Bild fertig ist. Erst dann kann ich es auslesen.
Bisher habe ich dass mit einem QTimer gelöst, der immer 2 ms wartet und dann die Funktion zum auslesen des bildes aufruft. Das Funktioniert zwar ist aber umständlich.
Jetzt wollte ich das einfacher mit einer for Schleife lösen die einfach in jedem Durchlauf die Daten setzt, kurz abwartet bis das Bild fertig ist und es dann ausliesst. Das warten habe ich probiert mit einem Sleep() call zu machen. Oder auch mit einer QWaitCondition die ich einfach austimen ließ. Das Problem ist, dass scheinbar trotz warten in der Zwischenzeit der Renderer nicht zum Zug kommt. Scheinbar wird der Prozess/Thread in der zwischenzeit nicht gewechset vom Scheduler(glaube ich halt).
Mir ist dabei nicht klar warum der Vorgang mit dem QTimer funktioniert, aber wenn ich Sleep()/Yield() aufrufe der Renderer nie dranzukommen scheint. Daher meine oben gestellte Frage.

thx und lg scr
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Dann lies mal die Doku zu deinem Renderer nochmal genau durch. Ich bin mir sicher da gibt es die Möglichkeit, einen Callback mitzugeben, der aufgerufen wird wenn das Bild fertiggerendert ist. Alles andere würde zu sehr auf die Performancebremse drücken bzw. auch zu Problemen führen, wenn z.B. dein Programm auf einem Rechner mit langsamerer Grafikkarte ausgeführt wird, wo eben nach 2ms das Bild noch nicht fertig ist...
sacrif
Beiträge: 40
Registriert: 22. Januar 2010 18:52

Beitrag von sacrif »

Da gibts leider noch nicht viel doku dazu - ist recht neu :)

Das Problem ist, dass ich vermute, dass der Renderer gar nicht erst drankommt, weil ich für jeden Durchlauf das gleiche Bild bekomme(dass er vor der Schleife angezeigt hat)

lg
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Wenn es noch kaum Doku gibt, würde ich den Programmierer/die Softwarefirma anhauen, wie du an das gerenderte Bild kommst. Wenn die tatsächlich ein Warten ohne irgend welche fertig()-Notifications vorsehen, würde ich den Renderer wechseln :/

Ansonsten kann man dir mit der bisherigen Beschreibung der Code-Versuche nicht wirklich helfen. Da braucht man was handfesteres - deinen Code.
Christian81
Beiträge: 7319
Registriert: 26. August 2004 14:11
Wohnort: Bremen
Kontaktdaten:

Beitrag von Christian81 »

QTimer ist hier schon die korrekte Wahl...
Noch besser wäre es wenn der Renderer selbst signalisieren würde wenn ein Bild fertig ist.

Alles andere ist... naja nicht schön.
MfG Christian

'Funktioniert nicht' ist keine Fehlerbeschreibung
sacrif
Beiträge: 40
Registriert: 22. Januar 2010 18:52

Beitrag von sacrif »

Danke mal für eure Antworten.
Ich hab gehofft, dass ich wenn ich genauer vestehe warum das mit dem Timer funktioniert, dass ich dann auch eine bessere Idee habe wie ich das Problem anders lösen könnte.

Ich weiss zwar nicht ob man aus diesem code viel rauslesen kann, aber so sieht mein derzeitiger Versuch aus das ganze ohne Timer zu lösen: (funktioniert nicht)

Code: Alles auswählen


void myClass::createThumbnails()
{
    for(unsigned int i = 0; i < thumbnailVector_.size(); i++)
    {
        QGradient gradient = thumbnailVector_[i]->getGradient();
        tfEditor_->setGradient(gradient); //sets data required by renderer to render the image
//hier irgendwie eine unterbrechung einbauen
//Zb.: Sleep(10); -->funktioniert nicht
        QImage* currentImage = getRenderedImage(); //reads out buffer from renderer

        thumbnails_.push_back(currentImage );
    }
}


QImage* myClass::getRenderedImage()
{
  Cuda::HostMemoryLocked<uchar4, 2>* renderedData = Renderer::getBuffer();

  QImage* currentImage = new QImage((uchar*)renderedData->getBuffer(),
                                    renderedData->size[0],               
                                    renderedData->size[1],            
                                    renderedData->getPitch(),           
                                    QImage::Format_ARGB32);
 
  return currentImage ;
}


Lösung mit Timer: funktioniert

Code: Alles auswählen

void myClass::createThumbnails()
{
    counter_ = 0; //global var
	QGradient gradient = thumbnailVector_[counter_]->getGradient();
    tfEditor_->setGradient(gradient);

    connect(timer_, SIGNAL(timeout()), this, SLOT(createCurrentThumbnail()));
    timer_->start(2);
}
    
    
myClass::createCurrentThumbnail()
{
      QImage* currentImage = getRenderedImage();
      thumbnails_.push_back(currentImage);
      ++counter_;
      //set tf for next iteration
      if(counter_ < thumbnailVector_.size())
      {
		QGradient gradient = thumbnailVector_[counter_]->getGradient();
        tfEditor_->setGradient(gradient);
      }
      else
      {
		 timer_->stop();
		 counter_ = 0;
		 disconnect(timer_, SIGNAL(timeout()), this, SLOT(createCurrentThumbnail()));
      }
}
Ich verstehe einfach nicht warum mit dem timer eine Unterbrechung da ist in der der Renderer arbeiten kann, aber durch ein sleep oder ähnliches nicht. Kann man den Timer vielleicht irgendwie innerhalb der for Schleife missbrauchen um an dieser Stelle ein "Warten" zu veranlassen?

lg[/code]
franzf
Beiträge: 3114
Registriert: 31. Mai 2006 11:15

Beitrag von franzf »

Das Sleep kommt doch direkt von Windows, oder? Versuchs mal mit qWait. Das ist eine nicht blockierende Variante zu qSleep. Blockiernd heißt, dass in dem während dem Warten der Prozess blockiert :P Es wird also nix gerechnet, der Prozess wird Schlfen gelegt.
RHBaum
Beiträge: 1436
Registriert: 17. Juni 2005 09:58

Beitrag von RHBaum »

Ich hab gehofft, dass ich wenn ich genauer vestehe warum das mit dem Timer funktioniert
nen timer funktioniert immer nur mit direkter oder indirekter Nebenlaeufigkeit !

direkte Nebenlaufigkeit:
Dein Framework oder dein BS erzeugt fuer den timer einen eigenen Prozess oder Thread, oder haengt den timer in einen anderen Prozess oder thread ein, wenn der Timer "reif" ist, wird der "empfaenger" benachrichtigt.

indirekte Nebenlaeufigkeit:
Dein Timer benutzt den Schduler vom BS. Der verteilt ja sowoieso die rechenzeit. unter den Prozessen / threads auf die kerne. Der Schduler bkommt also eintraege, wenn er Timer callen (meist über Signale realisiert) muss. Da springt er einen "Hilfszweig" (SignalHaendler) an, der ein Event in eine bestimmte Eventloop einhaengt.
Das funktioniert sowieso voellig transparent im Hintergrund.

Egal welche version du nutzt, funktionieren tut es fuer dich gleich.
Du erzeugst in deinem Thread den Timer. Der timer erzeugt den Thread oder durchlauft den code im BS-Kern, der den scheduler modifiziert, bzw eintrage in die timertables macht. kehrt dann sofort zu dir zurueck.
Du arbeitest lustig in deinem Programm weiter, der scheduler teilt dir rechenzeit zu und entzieht sie dir wieder ... du merkst eh nix davon. ^^

wird der timer reif, springt der scheduler ned dein programm, sondern nen signalhaendler an, oder der andere thread weckt auf, bzw mekrt das dein timer reif iss, und springt zu nem entsprechenden codefragment.
dort wird nix anderes gemacht, als in deiner Eventloop ein eintrag erzeugt vom typ timer. dann laufen die Handler wieder aus, bzw der thread macht dann was er noch machen muss.

Deine App bekommt irgendwann wieder rechenzeit, befindet sich aber irgendwo, einzig was sich fuer sie geaendert hat, iss das sie jetzt nen timer eintrag in der eventloop hat.
Irgendwann kommt die App wieder zum abarbeiten der eventloop. Je nach system steht dann der timer ganz vorn oder hinten an ...
egal, irgendwann arbeitet die app diesen eintrag ab und voiala du fliegst in deine Timer behandlungsroutine ....

Das schoene: Du hasst bis dahin nix mit Nebenlaeufigkeit zu tun gehabt. Timer sind also ne Methode Nebenlaeufigkeiten zu vermeiden, wenn das problem simple genug iss. Wirds etwas komplexer, sollt man scho nebenlauefigkeit verwenden (threads/prozesse) ...

Hoffe das hat fuers verstaendniss geholfen.

Ciao ....
sacrif
Beiträge: 40
Registriert: 22. Januar 2010 18:52

Beitrag von sacrif »

Ahh...danke franzf!!! Du bist mein Held :D :D Des funktioniert super - is zwar sicher noch Verbesserungswürdig der Ansatz, aber daweil is des echt eine große Erleichterung für mich beim Arbeiten(bis halt richtige notifications eingebaut sind - oder ich weiss wie ich ran komm) :)

@ RHBaum: Auch vielen Dank für die Mühe der ausführlichen Beschreibung!

lg scr
Antworten