Registriert: Do Jan 03, 2013 04:07 Beiträge: 4
Programmiersprache: AutoIt, Delphi
Hallo,
ich schreibe grade eine Serveranwendung für einen Frogger Klon. Die Serveranwendung soll u.a. Autos mit möglichst konstanter Geschwindigkeit fortbewegen. Im (noch Singleplayer) Client wurde ein auf 5ms "getakteter" TTimer verwendet, welcher effektiv aber nur alle ~15ms "feuert". Die Serveranwendung soll nun eine präzisere Variante benutzen. Ich habe eine whileschleife in einem eigenen Thread welche die Prozedur in der die Autos bewegt werden auslöst. Das mit der Zeit habe ich versucht so zu Lösen.
Code:
while true do begin
oldtime := gettickcount;
synchronize(FmServer.MainLoop);
sleeptime := gettickcount - oldtime;
if sleeptime < 5 then begin
sleep(5-sleeptime);
end;
Geplant sind also, mindestens 5ms vergehen zu lassen. Da das Bewegen der Autos und auch die anderen Berechnungen nicht sehr komplex sind sollte es eigentlich kein Problem sein die Schleife schneller als in 5ms zu durchlaufen. Wenn dem so war, wird die Restzeit abgewartet.
Die eigentliche Frage. Wie sieht die elegantere Möglichkeit aus, eine Schleife mit möglichst konstanter Frequenz/Rate zu Wiederholen?
MfG donald
Zuletzt geändert von donald am Mi Jun 11, 2014 21:54, insgesamt 1-mal geändert.
Registriert: Di Apr 29, 2008 18:56 Beiträge: 1213
Programmiersprache: Delphi/FPC
Hey,
das ist nur schwer möglich. Bei Windows wirst du _nie_ unter 16ms kommen, weil das die kleinste Zeiteinheit ist, die ein Thread schlafen gehen kann. Um wirklich ein genaues sleep zu bekommen könntest du dir eine while(true) Schleife bauen, mit QueryPerformanceCounter die Zeit berechnen und wenn die Wartezeit vorbei ist die Schleife beenden, das ist aber in heutigen Programmen eher ein NO-GO! Moderne Programme arbeiten alle mit TimeBased-Movement. Hier ein wenig pseudo-Code:
//ggf warten damit der Thread nicht mit 100% CPU-Last läuft (oder andere notwendige Dinge berechnen)
sleep(5);
Mit de Methode hast du zwar immer noch kein genaues Intervall, dafür aber eine genaue Bewegnung, da die Bewengung der Objekte von der Zeit abhängig ist.
€: 5ms sind meiner Meinung nach auch völlig übertrieben, 50ms sollten völlig ausreichend sein. Ich schalte bei meinem OpenGL Programmen immer vSync an, dann blockiert SwapBuffers solange bis der Monitor bereit ist ein neues Bild auszugeben. Bei einem 60Hz Monitor wären das ca. 16ms.
Registriert: Mi Aug 14, 2013 21:17 Beiträge: 588
Programmiersprache: C++
Bergmann89 hat geschrieben:
Bei Windows wirst du _nie_ unter 16ms kommen, weil das die kleinste Zeiteinheit ist, die ein Thread schlafen gehen kann.
Das habe ich schon oft gelesen, was aber nichts daran ändert, dass es schlicht falsch ist. Um sicher zu gehen, habe ich es gerade nochmal ausgetestet. Ein Sleep(0) hat in einem Fall sogar nur 1 µs gebraucht.
Bergmann89 hat geschrieben:
Moderne Programme arbeiten alle mit TimeBased-Movement.
Ist richtig, hat aber mit dem Problem nichts zu tun. Timebased Movement dient lediglich dazu, das Spielgeschehen auf verschieden schnellen Rechnern gleichschnell ablaufen zu lassen. Eine schwankende Framerate führt aber auch mit TBM unweigerlich zu Mikrorucklern (wobei das "Mikro" nicht "winzig" bedeutet, sondern nur die Art des Rucklers klassifiziert).
Bergmann89 hat geschrieben:
50ms sollten völlig ausreichend sein
50 ms entsprechen 20 fps. Das ist zum Rendern zu wenig.
Vorsicht übrigens: sleep() (POSIX) und Sleep() (Windows) sind nicht dasselbe. Ersteres erwartet eine Zeitangabe in Sekunden und letzteres in Millisekunden.
_________________ So aktivierst du Syntaxhighlighting im Forum: [code=pascal ][/code], [code=cpp ][/code], [code=java ][/code] oder [code=glsl ][/code] (ohne die Leerzeichen)
Registriert: Di Apr 29, 2008 18:56 Beiträge: 1213
Programmiersprache: Delphi/FPC
Hey,
glAwesome hat geschrieben:
Das habe ich schon oft gelesen, was aber nichts daran ändert, dass es schlicht falsch ist. Um sicher zu gehen, habe ich es gerade nochmal ausgetestet. Ein Sleep(0) hat in einem Fall sogar nur 1 µs gebraucht.
sleep(0) ist eine Ausnahme und kehrt sofort zurück. Alles was drüber ist wartet mindestens die Zeit eines System Ticks und der ist bei Windows 16ms: Hier steht alles schwarz auf weiß.
glAwesome hat geschrieben:
Ist richtig, hat aber mit dem Problem nichts zu tun. Timebased Movement dient lediglich dazu, das Spielgeschehen auf verschieden schnellen Rechnern gleichschnell ablaufen zu lassen. Eine schwankende Framerate führt aber auch mit TBM unweigerlich zu Mikrorucklern (wobei das "Mikro" nicht "winzig" bedeutet, sondern nur die Art des Rucklers klassifiziert).
Da geb ich dir recht, aber da es hier um den Server geht hat man auch dementsprechend kein Bild. Der kümmert sich nur um die Bewegung und da sollten auch 50ms ausreichend sein. Den Microrucklern kann man mit Double- oder Tripple-Buffering entgegen wirken. Ich hatte da mal n sehr gutes White-Paper dazu, das find ich aber leider nicht mehr
Da steht nur, dass Sleep höchstens so genau wie ein System Tick ist. Dass dieser 16 ms lang ist, steht da nicht und das ist auch nicht wahr. Andere Zeiten, die ich vorhin (nicht mit 0) gemessen habe, waren irgendwas mit 2700 µs und 6100 µs. Und nochmal möchte ich auf den Unterschied der beiden Funktionen hinweisen, da du schon wieder ein kleines s geschrieben hast, dein Link aber auf Sleep verweist.
Bergmann89 hat geschrieben:
da es hier um den Server geht hat man auch dementsprechend kein Bild. Der kümmert sich nur um die Bewegung und da sollten auch 50ms ausreichend sein.
OK, das kann je nach Anwendung durchaus sein. Wenn allerdings der Server nur alle 50 ms die Autos weiterbewegt und die Clients das einfach übernehmen, bringt es auch nix, denn wenn der Client 100 fps hat aber 5 Frames hintereinander das selbe Bild zeigt, hat man effektiv wieder nur 20 fps.
Bergmann89 hat geschrieben:
Den Microrucklern kann man mit Double- oder Tripple-Buffering entgegen wirken.
_________________ So aktivierst du Syntaxhighlighting im Forum: [code=pascal ][/code], [code=cpp ][/code], [code=java ][/code] oder [code=glsl ][/code] (ohne die Leerzeichen)
Registriert: Di Mai 18, 2004 16:45 Beiträge: 2622 Wohnort: Berlin
Programmiersprache: Go, C/C++
http://wiki.delphigl.com/index.php/Frameratenbegrenzung Ich hatte eigentlich gehofft, dass der Artikel es erklärt aber scheinbar war ich nicht gut genug da drin. Sleep(1); sagt das der Prozess-Thread 1ms schlafen soll und nicht wie lange er wirklich schlafen wird. Wie lange der Thread wirklich schläft, hängt davon ab, wie lang die Time-Slice ist, wo im Slice der Thread gerade ist, wie genau der Timer ist, wie viele Kerne verfügbar sind und was die anderen Prozesse machen.
http://msdn.microsoft.com/en-us/library/windows/desktop/ms685100%28v=vs.85%29.aspx Die Priorität bestimmt die Time-Slices, Agner Fog hatte geschrieben, dass in seinen Studien raus kam, dass Normale Prozesse 16ms Slices haben und Echtzeit Prozesse 120ms. Wenn man nun ein Normalen Prozess für 16ms schlafen legt und der PC nur 1 Kern hat, dann würde ein Echtzeit Prozess, der keine System Funktionen aufruft und seine volle Zeit nutzt dafür sorgen, dass der normale Prozess minestens 120ms schlafen würde.
Mitglieder in diesem Forum: 0 Mitglieder und 25 Gäste
Du darfst keine neuen Themen in diesem Forum erstellen. Du darfst keine Antworten zu Themen in diesem Forum erstellen. Du darfst deine Beiträge in diesem Forum nicht ändern. Du darfst deine Beiträge in diesem Forum nicht löschen. Du darfst keine Dateianhänge in diesem Forum erstellen.