Timer...



  • Liebe C-PlusPlus-Forum,

    ich habe ein kleines Problem und erhoffe mir eure Hilfe :). Es geht darum, dass ich Millisekunden genau arbeiten muss und das Programm nicht unnötig auf einer 100% Last haben möchte. Aber der Reihe nach.

    Ich möchte, dass alle X ms bestimmte Methoden ausgeführt werden. Dabei sollte das ausführen ms genau sein. Ich habe herausgefunden, dass es mit den Timern der MFC nicht ganz geht, diese sind zu ungenau. Viel genauer (sogar sehr genau) geht es mit QueryPerformanceCounter(). Nun habe ich also "Timer" geschrieben, welche darauf basieren. Das Problem ist nun, dass meine Timer in einer while-Schleife geprüft werden, ob die Zeit dieser verstrichen ist (wie gesagt das klappt alles super).

    while (TRUE) {
    
    	// Timer prüfen und ausführen	
    	pItor = m_oTimers.begin();
    	while (pItor != m_oTimers.end()) {
    		pTimer = pItor->second;
    
    		// Prüfen ob der Timer ausgeführt werden muss
    		if (pTimer->IsDue()) {
    			// TimerFunction aufrufen
    			pTimer->GetFunction();
    		}
    		pItor++;
    	}
    
    	// Soll die Rechnerauslastung runterschrauben (glaube ich aber nicht...)
    	Sleep(0);
    }
    

    Nun ist aber die Systemlast der Anwendung immer auf 100% (auch ein Sleep(0) in der while-Schleife hilft da nicht).

    Hat irgendjemand eine Idee... ich kann bestimmen wie lang die Anwendung warten kann (Sleep ist aber auch wieder sehr ungenau!). Ich bräuchte irgendwie ein Event, dass mir sehr genau sagt, dass die Zeit um ist und der nächste Timer aktiv werden soll.

    Ich hoffe man versteht mich, ansonsten nochmals nachfragen. Ich bin für jeden Ratschlag dankbar.

    Danke im Voraus
    Kurt



  • 1. Windows ist kein Echtezti-OS somit sind ms-genau Timer unmöglich
    2. Wenn es annähernd geht, dann nur mit den Multi-Media Timern (timeBeginPeriod/timeSetEvent)



  • Wie genau brauchst Du es denn? SetTimer ist dafür da eine Funktion OnTimer wiederholt aufzurufen. Die Multimedia-Timer und auch QueryPerformanceCounter() sind dafür da, Zeitdifferenzen zu messen. Mit letzterem kommt man auch sehr genau unter die 1 ms Schranke. Das heißt nicht, dass man Funktionen zeitgenau aufrufen kann. Das liegt, wie Jochen schon sagte, das Windows kein Echtzeit-OS ist.



  • Also mit dem QueryPerformanceTimer() bin ich eigentlich sehr genau. Soll heißen mir reicht diese Genauigkeit (nach meinen Messungen liegt diese wie Andy schrieb unter der 1ms). Die Funktion möchte ich schon "ziemlich" zeitgenau aufrufen. Wie gesagt klappt das bis jetzt auch gut mit der unten genannten Methode. Die Methode IsDue vergleicht dabei den letzten Aufruf mit der "aktuellen Zeit" (über QueryPerformanceTimer). Das Problem ist nur das mein Programm immer eine Systemlast von 100% hat. Das liegt natürlich daran, dass die Schleife voll läuft. Von daher suche ich dafür eine LÖsung :).

    Gibt es eine Seite um nachzusehen wie genau die Timer sind und auf denen einige aufgelistet sind. Ich habe gelesen, dass der Timer von Windows (OnTimer, SetTimer, ...) um die +/-50ms ungenau ist. Wie ist es mit Timeouts unter Windows? Wie genau ist z.B. der WaitForSingleObject Timeout? Gibt der annähernd im ms Bereich zurück in dem man das ganze angibt oder ist da auch ein Versatz von 50ms drin?

    Mit ist schon klar, dass Windows kein Echtzeitsystem ist und dass es bei starker Auslastung auch zu Differenzen kommen kann. Nicht desto trotz, möchte ich schon annähernd gute Ergebnisse erhalten. Deswegen jetzt schonmal vielen Dank für eure Hilfe.



  • Man muss glaub ich bei der SetTimer/OnTimer unterscheiden, in welchem Bereich man sich befindet. Zeiten kleiner 10 ms sind da generell nicht drin. Liegt ja auch in der Funktionsweise. Die OnTimer wird ja mittels WM_TIMER ausgelöst und die Nachrichtenbehandlung braucht seine Zeit. Ggf. läuft Deine Nachrichtenschleife zu.
    Das Problem mit der Systemlast hab ich auch. Dazu hatte ich vor kurzem hier schon mal einen Thread laufen. Allerdings hab ich mich jetzt damit abgefunden, da der Rechner eh nur die Maschine steuern soll und die zeitkritischen Abschnitte eher in der Minderzahl sind. Klar, elegant ist diese Lösung nicht.
    Seiten über timer gibts, da musst Du einfach mal googeln.



  • Hallo Forum,

    ich habe nun mal alles versucht auf Multimediatimer umzustellen. Ich war sehr begeistert als ich gesehen habe, dass diese Timer auch mit Events arbeiten können (timeSetEvent kann als dritten Parameter ein Handle auf ein Event erhalten). Nun habe ich mir gedacht, dass ich dort einfach von einem CEvent das m_hObject übergebe. Natürlich gecastet auf LPTIMECALLBACK und mit dem Parameter TIME_CALLBACK_SET. Leider geht das so nicht wirklich. Es gibt zwar keinen Fehler jedoch wird der Zeiger immer mit einer id von NULL erzeugt (was auf einen Fehler deutet). Woran kann das liegen?

    Danke für Hilfe
    Kurt



  • Die Zeile Code zum Erzeugen des Timers:

    MMRESULT m_iTimerID = ::timeSetEvent(iInterval, M_IACCURACY, (LPTIMECALLBACK) m_oTimer.m_hObject, NULL, TIME_PERIODIC | TIME_CALLBACK_EVENT_SET | TIME_KILL_SYNCHRONOUS);
    

Anmelden zum Antworten