[gelöst] Zeitauflösung von Sleep und co. erhöhen?



  • Hallo zusammen,

    die 16 ms zwischen den Logmeldungen kommen deshalb zustande,
    weil es meiner erfahrung nach unter windows (XP) nicht möglich ist sich in kleineren Zeitintervallen (auf nichts) zu suspendieren.

    So sorgt z.B. ein Sleep (1) immer für eine Wartezeit von ca. 16 [ms].

    Möchte man kleinere Zeitabstände ohne CPU Last warten,
    so ist daß meines Wissens nach nur IRQ getrieben per Treiber,
    z.B. über Hardwaretimer möglich.

    timeBeginPeriod sollte jedoch laut Doku dieses Verhalten beeinflusssen.
    Von dieser Funktion wusste ich bisher noch nicht.

    @Dobi
    Unter http://msdn.microsoft.com/en-us/library/ms686298(VS.85).aspx
    steht etwas mehr zu Sleep, timeBeginPeriod und timeGetDevCaps.

    Leider auch fast das was ich schon gesagt habe:

    "... In my experience, if you set dwMilliseconds to a value greater than 0 but less than one tick (e.g. Sleep(1);), the thread will sleep for at least one tick. So if one tick is 1/64 second (15.625ms), and you Sleep(1);, your thread will (in my experience) sleep for at least 15.625ms ..."

    Gruß Frank



  • Sleep(...) kann man prima durch nen Waitable Timer ersetzen:

    // Einmal erzeugen:
    HANDLE waitHandle = CreateWaitableTimer(NULL, true, NULL);
    
    // Dieser Teil wäre jeweils unser Sleep()-Aufruf:
    ///////////////////////////////////////////////////
    LARGE_INTEGER DueTime;
    // Hier DueTime setzen (in 100ns Einheiten)
    
    // Timer setzen:
    SetWaitableTimer(waitHandle, &DueTime, 0, NULL, NULL, false);
    
    // Auf den Timer warten (frisst keine CPU-Power):
    WaitForSingleObject(waitHandle,INFINITE);
    
    ///////////////////////////////////////////////////
    
    // Wenn der Timer irgendwann nicht mehr gebraucht wird, aufräumen:
    CloseHandle(waitHandle);
    

    ...das scheint zumindest auf meinem System gegenüber Sleep() ziemlich genau zu sein. Das Ding kann (wenn man den letzten Parameter bei SetWaitableTimer auf true setzt) scheinbar sogar das System wieder aus dem Standby holen...



  • Hallo geeky,

    was ist denn "ziemlich genau" ?

    Es geht darum weniger als 15 ms (z.B. 3 ms) zu Warten ohne busy zu laufen.

    Danke Gruß Frank



  • Auf meinem System (Win7, 64bit) schafft das scheinbar 1-2ms (allerdings weiss ich nicht ob man dem C# DateTime-Dingen da trauen kann, GetTickCount()-Differenz liefert 0)



  • Frank Erdorf schrieb:

    Hallo Dobi,
    wie siet denn

    ZeitAusgabeTest
    

    aus ?
    Danke, Gruß Frank

    Ich polle ständig die Zeit und gebe sie aus sobald sie sich geändert hat.

    lowbyte_ schrieb:

    Hi
    Denke dass bei dir die Funktion ZeitAusgabeTest(); zu viele Cpu cycles braucht! Daher die schlechte Performance.
    Lowbyte

    Nein, daran liegt es nicht. Wenn ich nach jedem Pollen ausgebe, habe ich die gleiche Zeit viele Male untereinander stehen und dann den Sprung.
    Das Pollen und die Ausgabe verbraucht also wesentlich weniger als die Vierundsechzigstelsekunde.

    _Luckie schrieb:

    Warum brauchst du eine so geringe Auflösung?

    Ich brauche eine so hohe Auflösung für das Timing bei der Kommunikation mit einer SPS.

    @Frank: Mir ist aufgefallen, dass ein Sleep von zb. 10 manchmal aber auch auch schon viel zu früh zurückkommt. Ich vermute mal, dass das passiert, wenn man es ganz kurz vor so einem Zeitsprung aufruft.

    @geeky: Werde deinen Vorschlag auch mal ausprobieren und dann berichten.



  • Ich weiß zwar nicht, was eine SPS ist, aber dir sollte bewusst sein, dass Windows kein Echtzeitbetriebssystem ist. Deswegen würde ich das Konzept noch mal überdenken.



  • Hi

    Klar ist Windows Echtzeit fähig ! Warum nicht ?

    lowbyte



  • Wegen dem Scheduling, du Schlaumeier



  • Hi

    Windows ist Echzeitfähig du schlaumeier. Da hilft dir dir ausrede von scheduler auch nicht !!!

    Du bist ein schlaumeier Und hasst wohl keine Ahnung.

    lowbyte



  • Hi

    Klar ist es wegen dem Scheduling nicht möglich genauer als 10ms zu sein. Doch 10ms sind Echtzeit !Und mich musst du nicht Schlaumeier nennen, ich weis von was ich rede ! ok!

    Nichts für ungut.

    lowbyte



  • Hi

    Poste mal was aus mikrocontroller.net

    Noch etwas zu den Betriebssystemen:

    Die Reaktionszeit auf ein Ereignis (Timerinterrupt oder externes
    Signal) hängt im Wesentlichen von den folgenden Faktoren ab:

    1. Zeit bis zum Aufruf des entsprechenden Interrupthandlers

    2. Zeit bis der Scheduler einen auf das Ereignis wartenden
    Anwendungsprozess/-thread aufgeweckt hat

    3. Zeit, die der Anwendungsprozess für die Bearbeitung benötigt

    Für 3 ist der Anwendungsprogrammierer verantwortlich. Mit schlechter
    Programmierung kann man die beste Echtzeitfähigkeit eines Betriebs-
    systems kaputt machen.

    Punkt 2 hängt von der Anzahl der laufenden Prozesse, deren Zustand
    (schlafend, aktiv) und deren Priorisierung ab. In Linux (und soviel
    ich weiß, auch in Windows) gibt es so genannte Real-Time-Threads, die
    Priorität über sämtliche gewöhnlichen Threads haben. Die Zeitdauer für
    deren Aufwecken sollte konstant sein und liegt schätzungsweise maximal
    in ein- bis zweistelligen µs-Bereich. Tatsächlich könnte es sein, dass
    diese Zeit noch etwas von der Gesamtzahl der existierenden Threads
    abhängt (kenne die internen Algorithmen nicht genau). Aber das sollte
    bei Echtzeitanforderungen im ms-Bereich keine Rolle spielen.

    Wenn von den Real-Time-Threads kein Gebrauch gemacht wird, hängt die
    Zeit bis zum Aufwecken sehr stark von anderen laufenden Anwendungen
    ab. Nur wenn man deren Verhalten genau kennt, ist eine Abschätzung der
    Zeit möglich. Sonst kann sie theoretisch beliebig hoch werden. Zu den
    "anderen Anwendungen" gehören nicht nur die vom Benutzer selbst,
    sondern auch die vom Betriebssystem automatisch gestarteten Prozesse
    (in Windows die Dienste, in Linux die Dämonen), so dass eine
    Abschätzung meist schwierig ist. Aber, wie gesagt, dies kann man mit
    den Real-Time-Threads in den Griff bekommen.

    Bleibt Punkt 1, die Zeit bist zur Ausführung des Interrupthandlers.
    Diese ist ebenfalls schwer abzuschätzen, da der Kernel und jeder
    Treiber die Möglichkeit hat, Interrupts für eine beliebig lange Zeit
    zu sperren. Die Zeit hängt also stark von den aktiven Treibern ab, die
    insbesondere bei Windows aus ganz unterschiedlichen Quellen stammen.
    Linux hat es da etwas leichter, da fast alle Treiber Bestandteil des
    offiziellen Kernelpakets sind. Baut ein Treiberentwickler exzessive
    Interruptsperren in seinen Code ein, wird ihm ziemlich schnell von
    anderen Kernelentwicklern auf die Finger geklopft. Bei Windows gibt es
    diese Kontrolle höchstens bei den von MS offiziell unterstützten
    Treibern.

    Ein weiterer Punkt, der speziell timergesteuerte Aktivitäten betrifft,
    ist die Timerauflösung. Sie beträgt bei Windows 10ms*, d.h. es ist
    Anwendungsebene unmöglich, zyklische Aktivitäten mit mehr als 100Hz zu
    realisieren (auf Treiberebene geht das schon, aber dann muss man eben
    in die Treiberprogrammierung einsteigen). Unter Linux beträgt die
    Auflösung wahlweise 10ms, 3ms oder 1ms, wobei letztere der Default bei
    Desktopsystemen ist.

    😉 Ah, habe gerade bei Heinz gelesen, dass auch 1ms möglich ist. Das
    habe ich vorher nicht gewusst.

    Da Linux in letzter Zeit immer häufiger in Steuerungsanwendungen
    eingesetzt wird, sind die Entwickler bestrebt, die Latenzzeiten weiter
    zu senken. So sind seit Version 2.6 die Kernelroutinen unterbrech-
    bar, was sie früher nicht waren und in Windows m.W. auch nicht sind.
    Ohne diese "Kernel-Preemption" blockieren Aufrufe von Kernelroutinen
    aus Anwendungsprogrammen (z.B. für I/O) das komplette System teilweise
    bis in den ms-Bereich.

    Zusätzlich gibt es für Linux den Real-Time-Patch von Ingo Molnar, der
    u.a. die Interruptsperrzeiten weiter verkürzt.

    Fazit:

    - Harte Echtzeit ist in Window und Standard-Linux nicht möglich.

    - Weiche Echtzeit geht bei Windows in der Größenordnung von 30ms.
    Beispiel aus eigener Erfahrung: Ein zyklischer Thread, der timer-
    gesteuert alle 100ms aktiviert wird, wies einen Jitter von ca.
    20 bis 30ms auf. Man muss aber mit sporadische Ausreißern rechnen,
    bei denen Verzögerungen bis in den Sekundenbereich auftreten.

    - Weiche Echtzeit geht in Linux in der Größenordnung von 4ms. Beispiel
    aus eigener Erfahrung: Ein zyklischer Thread, der timer- gesteuert
    alle 5ms aktiviert wird, wies einen Jitter von ca. 2ms auf. Sporadi-
    sche Ausreißer lagen in der Größenordnung von 20ms. Man muss aber
    dazu sagen, dass es sich um eine sehr schlanke Linuxinstallation
    handelte, bei der nur der Anwendungs- und die nötigsten System-
    prozesse aktiv waren. Der Kernel war aber standardmäßig und
    ungepatcht.

    - "Fast" harte Echtzeit geht in Linux mit dem Real-Time-Patch im
    Bereich von 200-400ns, hab's aber selber noch nicht intensiv
    getestet. Infos gibt's z.B. hier:

    http://www.captain.at/howto-linux-real-time-patch.php

    - Richtig hart und schnell geht es mit speziellen Real-Time-Kerneln,
    die praktisch unter den normalen Kernel geschoben werden und diesen
    als niederpriorisierten Thread ausführen. Beispiele: RT-Linux (schon
    mal gestestet) und RTAI, für Windows gibt's wohl vergleichbares.
    Damit lassen sich Latenzzeiten erreichen, die garantiert im
    µs-Bereich liegen, erreichen. Nachteil: Das API für System- und
    I/O-Funktionen unterscheidet sich prinzipbedingt von dem, was man
    gewohnt ist, so dass man sich in die Programmierung erst einarbeiten
    muss. Es gibt aber Kommunikationschnittstellen zwischen Echtzeit-
    und Nichtechtzeitebene, so dass man i.Allg. nur einen kleinen Teil
    einer Anwendung für die Ausführung in dieser "Kellerebene" portieren
    muss.

    Anmerkung: Die angegeben Zahlenwerte sind keine fundierten Messdaten
    und hängen auch natürlich stark von der eingesetzten Hardware ab. Sie
    sollen lediglich einen Eindruck der Größenordnungen vermitteln.

    lowbyte



  • Hi

    Es ist ummöglich wie gesagt, auf Anwendungsebene eine höhere Auflösung von 10ms zu erreichen. Mit einem Treiber ist das möglich.. aber da sollte man doch schon was von der Treiberprogrammierung verstehen.

    lowbyte



  • Hi

    Wen du nicht mit Treiberprogrammierung weiterfahren möchtest, kannst du mit SetPriorityClass() ,und SetThreadPriority den Process Priorisieren.

    -> REALTIME_PRIORITY_CLASS

    SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);

    []
    Process that has the highest possible priority. The threads of the process preempt the threads of all other processes, including operating system processes performing important tasks. For example, a real-time process that executes for more than a very brief interval can cause disk caches not to flush or cause the mouse to be unresponsive.
    [
    ]

    Damit solltest du Auflösungen von 10-12 ms haben.

    lowbyte



  • @_Luckie: Dass Windows eigentlich nicht für sowas gedacht ist, und man mit seinen sleeps auch immer Pech haben kann, und die erst irgendwann zurückkommen können, ist mir klar. Dass das Programm unter XP zu laufen hat, kann ich jetzt aber leider auch nicht ändern.

    @lowbyte_: Ganz ruhig. 😉
    Dass eine höhere Zeitauflösung (1ms und besser) unter Windows auf Anwendungsebene prinzipiell möglich ist, sieht man ja daran, dass man sich mit QueryPerformanceCounter wunderbar eine sehr präzise Zeit ausgeben lassen kann. Nur die präzisen kurzen Schläfchen klappen halt nicht.
    Es sieht so aus, als ginge bei XP nichts in Richtung High Precision Event Timer.



  • Hi

    Lies den Beitrag eins oben. Damit kannst du genauere Auflösungen auf anwendungsebene erreichen.

    gruss lowbyte



  • lowbyte_ schrieb:

    Wen du nicht mit Treiberprogrammierung weiterfahren möchtest, kannst du mit SetPriorityClass() ,und SetThreadPriority den Process Priorisieren.

    -> REALTIME_PRIORITY_CLASS

    Dann sagt ihm aber bitte auch gleich, wo er den Resetknopf am Gehäuse findet.



  • Ich habe deinen Beitrag gelesen, und mir ist klar, dass das Sceduling meinem Thread gegenüber freundlicher wird, wenn ich die Priorität erhöhe.
    Eine Auflösung von 10-12ms würde mir zwar auch nicht reichen, ich habe deinen Vorschlag aber trotzdem mal umgesetzt.

    #include <windows.h>
    #include <stdio.h>
    
    int main()
    {
    	SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
    	bool waitForTimeChange = true;
    	SYSTEMTIME st;
    	unsigned long timeInMs( 0 );
    	unsigned long timeInMsOld( 0 );
    	int outputCount( 0 );
    	while ( outputCount < 20 )
    	{
    		GetSystemTime(&st);
    		timeInMsOld = timeInMs;
    		timeInMs = 24*60*1000* st.wHour + 60*1000*st.wMinute + 1000*st.wSecond + st.wMilliseconds;
    		if ( !waitForTimeChange || ( timeInMs != timeInMsOld ) )
    		{
    			printf("%d.%d.%d %d:%d:%d.%d\n" ,st.wDay,st.wMonth,st.wYear,st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
    			++outputCount;
    		}
    	}
    	return 0;
    }
    

    Die dazu gehörige Ausgabe sieht so aus:

    25.6.2010 10:43:36.375
    25.6.2010 10:43:36.390
    25.6.2010 10:43:36.406
    25.6.2010 10:43:36.421
    25.6.2010 10:43:36.437
    25.6.2010 10:43:36.453
    25.6.2010 10:43:36.468
    25.6.2010 10:43:36.484
    25.6.2010 10:43:36.500
    25.6.2010 10:43:36.515
    25.6.2010 10:43:36.531
    25.6.2010 10:43:36.546
    25.6.2010 10:43:36.562
    25.6.2010 10:43:36.578
    25.6.2010 10:43:36.593
    25.6.2010 10:43:36.609
    25.6.2010 10:43:36.625
    25.6.2010 10:43:36.640
    25.6.2010 10:43:36.656
    25.6.2010 10:43:36.671
    

    Es bringt also nichts. Warum auch, es war ja eh kein anderer Prozess im Weg, der ordentlich Rechenzeit verbraucht hätte.

    Jetzt möchte ich gerne den Beleg nachliefern, dass es nicht daran liegt, dass meine Ausgabe zuviel Rechenzeit verbraucht:

    #include <windows.h>
    #include <stdio.h>
    
    int main()
    {
    	bool waitForTimeChange = false;
    	SYSTEMTIME st;
    	unsigned long timeInMs( 0 );
    	unsigned long timeInMsOld( 0 );
    	int outputCount( 0 );
    	while ( outputCount < 20 )
    	{
    		GetSystemTime(&st);
    		timeInMsOld = timeInMs;
    		timeInMs = 24*60*1000* st.wHour + 60*1000*st.wMinute + 1000*st.wSecond + st.wMilliseconds;
    		if ( !waitForTimeChange || ( timeInMs != timeInMsOld ) )
    		{
    			printf("%d.%d.%d %d:%d:%d.%d\n" ,st.wDay,st.wMonth,st.wYear,st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
    			++outputCount;
    		}
    	}
    	return 0;
    }
    

    ->

    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.750
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    25.6.2010 10:23:41.765
    

    Setze ich jetzt timeBeginPeriod(1); davor, wird es leider auch nicht besser:

    #include <windows.h>
    #include <stdio.h>
    
    int main()
    {
    	timeBeginPeriod( 1 );
    	bool waitForTimeChange = true;
    	SYSTEMTIME st;
    	unsigned long timeInMs( 0 );
    	unsigned long timeInMsOld( 0 );
    	int outputCount( 0 );
    	while ( outputCount < 20 )
    	{
    		GetSystemTime(&st);
    		timeInMsOld = timeInMs;
    		timeInMs = 24*60*1000* st.wHour + 60*1000*st.wMinute + 1000*st.wSecond + st.wMilliseconds;
    		if ( !waitForTimeChange || ( timeInMs != timeInMsOld ) )
    		{
    			printf("%d.%d.%d %d:%d:%d.%d\n" ,st.wDay,st.wMonth,st.wYear,st.wHour,st.wMinute,st.wSecond,st.wMilliseconds);
    			++outputCount;
    		}
    	}
    	timeEndPeriod( 1 );
    	return 0;
    }
    

    ->

    25.6.2010 10:25:56.640
    25.6.2010 10:25:56.656
    25.6.2010 10:25:56.671
    25.6.2010 10:25:56.687
    25.6.2010 10:25:56.703
    25.6.2010 10:25:56.718
    25.6.2010 10:25:56.734
    25.6.2010 10:25:56.750
    25.6.2010 10:25:56.765
    25.6.2010 10:25:56.781
    25.6.2010 10:25:56.796
    25.6.2010 10:25:56.812
    25.6.2010 10:25:56.828
    25.6.2010 10:25:56.843
    25.6.2010 10:25:56.859
    25.6.2010 10:25:56.875
    25.6.2010 10:25:56.890
    25.6.2010 10:25:56.906
    25.6.2010 10:25:56.921
    25.6.2010 10:25:56.937
    

    Und hier noch mein Beispiel mit QueryPerformanceCounter:

    #include <windows.h>
    #include <iostream>
    
    using namespace std;
    
    int main()
    {
    	bool waitForTimeChange = true;
    
    	SYSTEMTIME initSystemTime;
    	GetSystemTime(&initSystemTime);
    	unsigned long initSystemTimeInMs = 24*60*1000* initSystemTime.wHour + 60*1000*initSystemTime.wMinute + 1000*initSystemTime.wSecond + initSystemTime.wMilliseconds;
    
    	LARGE_INTEGER PerformanceCounterTicksPerSecond;
    	QueryPerformanceFrequency(&PerformanceCounterTicksPerSecond);
    
    	LARGE_INTEGER PerformanceCounterTicksAtInit;
    	QueryPerformanceCounter(&PerformanceCounterTicksAtInit);
    
    	LARGE_INTEGER performanceCounterActualTicks;
    
    	unsigned long timeInMs( 0 );
    	unsigned long timeInMsOld( 0 );
    
    	int outputCount( 0 );
    	while ( outputCount < 20 )
    	{
    		QueryPerformanceCounter(&performanceCounterActualTicks);
    		timeInMsOld = timeInMs;
    		timeInMs = static_cast<unsigned long>( ( ( performanceCounterActualTicks.QuadPart - PerformanceCounterTicksAtInit.QuadPart ) / ( PerformanceCounterTicksPerSecond.QuadPart / 1000 ) ) + initSystemTimeInMs);
    		if ( !waitForTimeChange || ( timeInMs != timeInMsOld ) )
    		{
    			cout << ( timeInMs / (24*60*1000) % 60 ) << ":" << ( timeInMs / (60*1000) ) % 60 << ":" << ( timeInMs / 1000 ) % 60 << "." << timeInMs % 1000 << endl;
    			++outputCount;
    		}
    	}
    	timeEndPeriod( 1 );
    	return 0;
    }
    

    ->

    11:47:56.687
    11:47:56.688
    11:47:56.689
    11:47:56.690
    11:47:56.691
    11:47:56.692
    11:47:56.693
    11:47:56.694
    11:47:56.695
    11:47:56.696
    11:47:56.697
    11:47:56.698
    11:47:56.699
    11:47:56.700
    11:47:56.701
    11:47:56.702
    11:47:56.703
    11:47:56.704
    11:47:56.705
    11:47:56.706
    

    So find ich das wunderbar, und werde die Zeit in Zukunft auf so abfragen.
    Mit 4 Millionen aufrufen, die mein normaler Rechner pro Sekunde von dieser Funktion schafft, ist sie auch nicht zu langsam.

    ...

    So, gerade eben habe ich den Vorschlag von geeky umgesetzt.

    #define _WIN32_WINNT 0x0400
    
    #include <windows.h>
    #include <process.h>
    #include <stdio.h>
    
    #include <iostream>
    
    using namespace std;
    
    SYSTEMTIME initSystemTime;
    unsigned long initSystemTimeInMs;
    LARGE_INTEGER PerformanceCounterTicksPerSecond;
    LARGE_INTEGER PerformanceCounterTicksAtInit;
    
    void printPreciseTime()
    {
    	LARGE_INTEGER performanceCounterActualTicks;
    	QueryPerformanceCounter(&performanceCounterActualTicks);
    	unsigned long timeInMs( static_cast<unsigned long>( ( ( performanceCounterActualTicks.QuadPart - PerformanceCounterTicksAtInit.QuadPart ) / ( PerformanceCounterTicksPerSecond.QuadPart / 1000 ) ) + initSystemTimeInMs) );
    	cout << ( timeInMs / (24*60*1000) % 60 ) << ":" << ( timeInMs / (60*1000) ) % 60 << ":" << ( timeInMs / 1000 ) % 60 << "." << timeInMs % 1000 << endl;
    }
    
    int main()
    {
    
    	GetSystemTime(&initSystemTime);
    	initSystemTimeInMs = 24*60*1000* initSystemTime.wHour + 60*1000*initSystemTime.wMinute + 1000*initSystemTime.wSecond + initSystemTime.wMilliseconds;
    	QueryPerformanceFrequency(&PerformanceCounterTicksPerSecond);
    	QueryPerformanceCounter(&PerformanceCounterTicksAtInit);
    
    	int outputCount( 0 );
    	while ( outputCount < 20 )
    	{
    		HANDLE waitHandle = CreateWaitableTimer(NULL, true, NULL);
    		LARGE_INTEGER DueTime;
    		FILETIME lpSystemTimeAsFileTime;
    		GetSystemTimeAsFileTime( &lpSystemTimeAsFileTime );
    		DueTime.HighPart = lpSystemTimeAsFileTime.dwHighDateTime;
    		DueTime.LowPart = lpSystemTimeAsFileTime.dwLowDateTime;
    		unsigned int waitTimeInMs( outputCount );
    		DueTime.LowPart += outputCount + waitTimeInMs*10*1000 ;
    		cout << "Target wait time in ms: " << waitTimeInMs << endl;
    		cout << "Start: ";
    		printPreciseTime();
    		SetWaitableTimer(waitHandle, &DueTime, 0, NULL, NULL, false);
    		WaitForSingleObject(waitHandle,INFINITE);
    		cout << "Stop: ";
    		printPreciseTime();
    		cout << endl;
    		CloseHandle(waitHandle); 
    		++outputCount;
    	}
    }
    

    ->

    Target wait time in ms: 0
    Start: 11:36:35.765
    Stop: 11:36:35.765
    
    Target wait time in ms: 1
    Start: 11:36:35.765
    Stop: 11:36:35.766
    
    Target wait time in ms: 2
    Start: 11:36:35.766
    Stop: 11:36:35.769
    
    Target wait time in ms: 3
    Start: 11:36:35.769
    Stop: 11:36:35.773
    
    Target wait time in ms: 4
    Start: 11:36:35.773
    Stop: 11:36:35.778
    
    Target wait time in ms: 5
    Start: 11:36:35.778
    Stop: 11:36:35.784
    
    Target wait time in ms: 6
    Start: 11:36:35.784
    Stop: 11:36:35.791
    
    Target wait time in ms: 7
    Start: 11:36:35.791
    Stop: 11:36:35.799
    
    Target wait time in ms: 8
    Start: 11:36:35.799
    Stop: 11:36:35.807
    
    Target wait time in ms: 9
    Start: 11:36:35.807
    Stop: 11:36:35.817
    
    Target wait time in ms: 10
    Start: 11:36:35.817
    Stop: 11:36:35.828
    
    Target wait time in ms: 11
    Start: 11:36:35.828
    Stop: 11:36:35.840
    
    Target wait time in ms: 12
    Start: 11:36:35.840
    Stop: 11:36:35.852
    
    Target wait time in ms: 13
    Start: 11:36:35.852
    Stop: 11:36:35.866
    
    Target wait time in ms: 14
    Start: 11:36:35.866
    Stop: 11:36:35.881
    
    Target wait time in ms: 15
    Start: 11:36:35.881
    Stop: 11:36:35.896
    
    Target wait time in ms: 16
    Start: 11:36:35.896
    Stop: 11:36:35.913
    
    Target wait time in ms: 17
    Start: 11:36:35.913
    Stop: 11:36:35.930
    
    Target wait time in ms: 18
    Start: 11:36:35.930
    Stop: 11:36:35.949
    
    Target wait time in ms: 19
    Start: 11:36:35.949
    Stop: 11:36:35.968
    

    Ja sehr schön! So scheints zu gehen. Vielen Dank, geeky. 🙂
    Meine Version da oben ist natürlich noch alles andere als Vollständigk (Überlauf vom LowPart usw.) aber ich werde mit diesem Ansatz jetzt mal weitermachen.
    Jetzt werde ich mal herausfinden, warum das überhaupt funktioniert, obwohl die Zeit, auf die ich meine Wartezeit aufaddiere ja eigentlich die ungenaue Systemzeit ist. 😉



  • Hi

    Trotzdem solltest du dir überlegen den Prozess zu priorisieren. Wen deine Cpu mal voll ausgelasstet ist, dan wirst du ohne die Priorisierung keine wirkliche echtzeit mehr haben.

    Ansonnsten hatt wohl geeky gut beschriben wie man auf Anwendungsebene echtzeit fahren kann, ohne gleich mit Treiber zu hantieren.

    Lowbyte



  • @Dobi:
    Deine "QueryPerformanceCounter" Zeit wird gegenüber der "echten" Zeit hübsch driften.



  • @lowbyte_:
    Wie wär's mit einfach mal die Fresse halten statt hier Unsinn über Echtzeitfähigkeit abzulassen?


Anmelden zum Antworten