Files |  Tutorials |  Articles |  Links |  Home |  Team |  Forum |  Wiki |  Impressum

Aktuelle Zeit: Do Okt 31, 2024 23:59

Foren-Übersicht » Programmierung » Allgemein
Unbeantwortete Themen | Aktive Themen



Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 
Autor Nachricht
BeitragVerfasst: Fr Jun 06, 2014 22:29 
Offline
DGL Member

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:
  1.   while true do begin
  2.     oldtime := gettickcount;
  3.     synchronize(FmServer.MainLoop);
  4.     sleeptime := gettickcount - oldtime;
  5.     if sleeptime < 5 then begin
  6.       sleep(5-sleeptime);
  7.     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.

Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Sa Jun 07, 2014 13:15 
Offline
DGL Member
Benutzeravatar

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:
Code:
  1. startTime = getCurrentTime();
  2. while(true)
  3.   //zeit delta ausrechnen
  4.   tmpTime = getCurrentTime();
  5.   deltaTime = tmpTime - startTime;
  6.   startTime = tmpTime;
  7.  
  8.   //Objecte bewegen
  9.   ObjectPosition = ObjectPosition + MovementVector * deltaTime;
  10.  
  11.   //ggf warten damit der Thread nicht mit 100% CPU-Last läuft (oder andere notwendige Dinge berechnen)
  12.   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.

MfG Bergmann.

_________________
Aktuelle Projekte: BumpMapGenerator, Massive Universe Online
Auf meiner Homepage gibt auch noch paar Projekte und Infos von mir.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Jun 12, 2014 09:30 
Offline
DGL Member
Benutzeravatar

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)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Jun 12, 2014 09:40 
Offline
Compliance Officer
Benutzeravatar

Registriert: So Aug 08, 2010 08:37
Beiträge: 460
Programmiersprache: C / C++ / Lua
Auch wenn schon geschlossen, meine Methode für Framelimit mit TBM:

Code:
  1.  
  2.   fLoop := true;
  3.   st := 0;
  4.   repeat
  5.     t := SDL_GetTicks;
  6.     Render;
  7.     HandleEvents;
  8.     //of course only if there's a fps-limit
  9.     if fMaxFPS > 0 then
  10.     begin
  11.       //calculate sleeptime
  12.       //there's no div-by-zero, cause fMaxFPS > 0
  13.       st := (1000 / fMaxFPS - (SDL_GetTicks - t)) + st;
  14.       if st > 0 then
  15.       begin
  16.         SDL_Delay(Trunc(st));
  17.         //added correction
  18.         //minimizes rounding-faults
  19.         st := st - Trunc(st);
  20.       end;
  21.     end;
  22.     //calculate fps
  23.     t := SDL_GetTicks - t;
  24.     timeofframe := t;
  25.     if t > 0 then
  26.       fFPS := Round(1000 / t);
  27.   until not fLoop;
  28.  


(SDL_Delay entspricht Sleep ; SDL_GetTicks entspricht dem QueryPerformanceCounter)

_________________
offizieller DGL Compliance Beauftragter
Never run a changing system! (oder so)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Jun 12, 2014 16:12 
Offline
DGL Member
Benutzeravatar

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 :(

MfG Bergmann

_________________
Aktuelle Projekte: BumpMapGenerator, Massive Universe Online
Auf meiner Homepage gibt auch noch paar Projekte und Infos von mir.


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Jun 12, 2014 17:08 
Offline
DGL Member
Benutzeravatar

Registriert: Mi Aug 14, 2013 21:17
Beiträge: 588
Programmiersprache: C++
Bergmann89 hat geschrieben:
Alles was drüber ist wartet mindestens die Zeit eines System Ticks und der ist bei Windows 16ms: Hier steht alles schwarz auf weiß.
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.
Nein, der Zusammenhang war anders: Triple-Buffering beseitigt das Problem der Frameraten-Halbierung beim Einsatz von V-Sync. Das wird allerdings mit zusätzlichen Mikrorucklern erkauft. Steht übrigens auch im Wiki:
http://wiki.delphigl.com/index.php/Framerate#Bildschirmfrequenz_und_V-Sync

_________________
So aktivierst du Syntaxhighlighting im Forum: [code=pascal ][/code], [code=cpp ][/code], [code=java ][/code] oder [code=glsl ][/code] (ohne die Leerzeichen)


Nach oben
 Profil  
Mit Zitat antworten  
BeitragVerfasst: Do Jun 12, 2014 21:41 
Offline
DGL Member
Benutzeravatar

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/ms682105%28v=vs.85%29.aspx
Sleep(0) hat SuspendThread Eigenschaften.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms684831%28v=vs.85%29.aspx
Das zeigt die Problematik von Thread Prioritäten und wenn systemfunktionen nicht nicht fertig werden.

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.

http://msdn.microsoft.com/en-us/library/windows/desktop/ms684247%28v=vs.85%29.aspx
Der Multimedia Timer läuft über ein anderen Sheduler, der es ermöglicht den normalen Sheduler zu umgehen.

_________________
"Wer die Freiheit aufgibt um Sicherheit zu gewinnen, der wird am Ende beides verlieren"
Benjamin Franklin

Projekte: https://github.com/tak2004


Nach oben
 Profil  
Mit Zitat antworten  
Beiträge der letzten Zeit anzeigen:  Sortiere nach  
Ein neues Thema erstellen Auf das Thema antworten  [ 7 Beiträge ] 
Foren-Übersicht » Programmierung » Allgemein


Wer ist online?

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.

Suche nach:
Gehe zu:  
cron
  Powered by phpBB® Forum Software © phpBB Group
Deutsche Übersetzung durch phpBB.de
[ Time : 0.012s | 17 Queries | GZIP : On ]