![]() |
Sleep bei hoher Systemauslastung zu lang
Hallo zusammen,
in meinem Programm nutze ich folgende "Pause"-Funktion, basierend auf MsgWaitForMultipleObjects:
Delphi-Quellcode:
Die Pause beträgt 1s. Mein Programm läuft mit normaler Priorität.
procedure Wait2(Milliseconds: Integer);
var Tick: DWord; Event: THandle; begin Event := CreateEvent(nil, False, False, nil); try Tick := GetTickCount + DWord(Milliseconds); while (Milliseconds > 0) and (MsgWaitForMultipleObjects(1, Event, False, Milliseconds, QS_ALLINPUT) <> WAIT_TIMEOUT) do begin Application.ProcessMessages; if Application.Terminated exit; Milliseconds := Tick - GetTickcount; end; finally CloseHandle(Event); end; end; Bei hoher Systemauslastung erhöht sich die Pause erheblich, ich vermute Timeout von MsgWaitForMultipleObjects funktioniert nicht richtig. Zu Testzwecken habe ich die Pausefunktion Wait2(1000) einfach durch Application.ProcessMessages ersetzt. Mein Programm läuft hierbei ausreichend schnell ab, ich denke also, dass ich die Priorität nicht erhöhen muss. Mit Sleep(1000) gibt es einen ähnlichen Effekt wie mit Wait2(1000). Vielleicht weiß hier jemand einen Rat, beste Grüße Seven |
Re: Sleep bei hoher Systemauslastung zu lang
Ich hab' es nicht ganz durchschaut aber wenn Du das im Hauptthread ausführst macht das Ding vielleicht dasselbe wie sleep und blockiert die Eventqueue und bremst damit das System aus. Denn während Du auf waitformultpleobjects wartest, steht der Thread still.
Grüße, Messie |
Re: Sleep bei hoher Systemauslastung zu lang
Du wirst nie, nie eine Pause von 1 ms Sekunde hinbekommen, wenn du Sleep o.ä. benutzt ;)
Der Grund ist einfach, dass Sleep die Zeitscheibe deines Prozesses sofort abgibt, und dir dann garantiert, dass du nach mindestens der angeebenen Zeitspanne wieder dran kommst. Zeitscheiben sind üblicherweise ein paar Millisekunden groß, so dass bereits ein Sleep(0) eine Verzögerung von über 20 ms geben sollte ;) Das gleiche Phänomen kann man beim Timer beobachten: Wenn man ihn auf 0 stellt, kommt das Event trotzdem nur alle 20ms ;) Bei hoher Systemauslastung sind halt andere Prozesse da, die auch Zeit wollen, und so verlängert sich die Zeit entsprechend ... |
Re: Sleep bei hoher Systemauslastung zu lang
Zitat:
Es ist aber so das durch den Auruf von Application.ProcessMessages; auch Nachrichten von Messagequeue genommen werden die die komplette Anwendung blockieren können. Zb. wm_NCLButtonDown, alos ein Klick mit der linken Maustaste in die Caption eines TForms. Versuche es und lass dabei die Maus ruhi liegen und die Maustaste gedrückt. Das Windows API für die Fenster verzweigt nämlich intern in eine Schleife die erst verlassen wird wenn man ie Maustaste wieder loßlässt. Das sind alte Artefakte eines veralteten Fensterhandlings im Windows aus 3.1. Zeiten stammend. Aber das kann auch dir selber passieren. Zb. eine beliebige Nachricht wie wm_Timer verzweigt in ein Timer1.OnTimer() Event das nun beginnt per Delay() ebenfalls zu warten. SOmit haben wird die Situation das aus einem Delay() -> Application.ProcessMessages -> Timer1.OnTimer() -> Delay() -> Application.ProcessMesages; -> usw. -> usw. aufgerufen wird. Als ich dieses Delay() hier in der DP vorstellte, als bessere Alternative zum noch schlechteren Sleep(), habe ich aber exakt darauf hingeweisen und auch begründet warum ein asynchroner Aufruf von Application.ProcessMessages; in jedem Falle eine schlechte Idee darstellt. Die VCL und Windows arbeiten Event-basiert also sollte man auch Warteschleifen Event-basiert aufbauen und nicht wie mit Sleep() oder Delay() durch Polling. Denn mit diesen Methoden pollt man die vergehende Zeit, bis genügend Zeit vergangen ist, statt wie bei einem Wecker eine Weckzeit einzustellen und dann nur auf das Klingeln des Weckers zu reagieren. Gruß Hagen |
Re: Sleep bei hoher Systemauslastung zu lang
Zitat:
Die beste Alternative, und auch die richtige, ist es auf Sleep(), Delay() und asynchrones Application.ProcessMessages, zu verzichten. Nehme einen TTimer, setze .Enabled auf False, dann .Interval auf X Millisekunden Warteseit, und dann .Enabled wieder auf True. Dann läuft deine Anwendung so weiter wi gewohnt und nach X Millisekunden lösst der TTimer ein Event aus. Innerhalb dessen dann .Enabled auf False setzen und die jeweilige Aktion ausführen. Sollten längerdauerende Berechnungen gemacht werden die quasi im Hintergrund ausgeführt werden sollen dann einfach mal über TThread nachdenken. Gruß Hagen |
Re: Sleep bei hoher Systemauslastung zu lang
Hallo,
jfheins schrieb: Zitat:
Hagens (negaH) Routine mit MsgWaitForMultipleObjects habe ich in einem anderen Projekt schon mal erfolgreich eingesetzt, danke übrigens. Dort kommuniziere ich alle 20ms mit einem an USB angeschlossenem Gerät und stelle Parameterdaten und Diagramm am PC dar. Das funktioniert sehr gut. Zuerst hatte ich das über TTimer realisiert, allerdings macht bei 20ms der Timer-Event Probleme, der erfolgt nämlich nicht so schnell, das liegt wohl am Zeitscheibenmodell von Windows. negaH schrieb: Zitat:
Die eigentliche Routine erfolgt dann nach dem eingestellten TimerIntervall und wird in OnTimer-EreignisRoutine ausgeführt, wobei man zuvor den Timer deaktiviert und nach der Routine wieder aktiviert, wenn die Routine periodisch aufgerufen werden soll. Ich probiere das mal aus, und beobachte, wie sich das bei hoher Systembelastung verhält. Gruß Seven |
Re: Sleep bei hoher Systemauslastung zu lang
Naja, wenn du alle 20ms ein Event benötigst dann wird das damit nicht gehen. Sowas ist schon schwieriger sauber unter Windows hinzubekommen. Ich würde dann Thread's benutzen, mit höher Priorität. Denoch bleibt der Tasksheduler von Windows und der sorgt dafür das Echtzeit unter Windows eben bei circa 20 Millisekunden und weniger aufhört zu existieren (aus Sicht einer Anwendung auf Ring 3, mit Kerneltreibern kommt man schon noch weiter runter )
Zitat:
Gruß Hagen |
Alle Zeitangaben in WEZ +1. Es ist jetzt 12:13 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz