Threads, Mutex oder CS und Geschwindigkeit?



  • Hi,
    Ich bin gerade an einem kleinen Netzwerkspiel mit SDL. Fürs Empfangen der Pakete nutze ich Threads. Habe also einen ServerReceive() und einen ClientReceive() Thread. Wenn Ich jetzt einen Gegner(oder was auch immer) hinzufüge, schickt der Server ein Paket an alle Clients (auch an sich selber) und im ClientReceive()-Thread wird dann der Gegner erstellt. Das alles ist natürlich in eine Klasse gepackt. Am Anfang hatte ich einfach Testweise globale Variablen alla:
    bool isMainActive, isSThreadActive, isCThreadActive;
    in den Threads und in der Hauptschleife hatte ich dann folgendes.

    isMainActive = true;
    while( isSThreadActive || isRThreadActive)
    	SDL_Delay(1);
    
    ... Code ..
    
    isMainActive = false;
    

    Naja und in den Threads halt das dazugehörige. Hat soweit auch super funktioniert ist ja aber nicht schön und sauber 🙂
    Nun hab ich Mutex und CriticalSection ausprobiert (GameLock = SDL_CreateMutex(); InitializeCriticalSection(&csGameLock); Natürlich nicht beides zusammen sonder nacheinander getestet. ), leider nur mit mäßigem Erfolg. Mit der ersten Variante konnte ich locker 200 Gegner auf meiner Map erstellen. Mit Mutex und CriticalSection fängt er bei 5 an zu stocken und wird richtig langsam.

    Ist das ein komplett Falscher Ansatz? Was hab ich noch für Möglichkeiten? Was würdet Ihr empfehlen? Wie wird das "richtig" gemacht :)?

    Das ganze Gebiet ist noch ziemlich neuland und bin noch nicht tief drinn 🙂

    MfG schirrmie



  • "richtig" wird es über Mutexen gemacht. Die "bool" Variante funktioniert nämlich nicht zuverlässig.

    BTW: Eine CRITICAL_SECTION *ist* eine Mutex (vom Konzept her), das was unter Windows MUTEX heisst ist nur eine andere Art von Mutex (die etwas mehr kann, was man aber selten braucht). Und eine CRITICAL_SECTION ist dramatisch schneller als das was Windows MUTEX nennt. Also auf jeden Fall eine CRITICAL_SECTION als Mutex verwenden.

    Schnell bekommt man das ganze dann indem man guckt dass man an so wenig Stellen wie möglich synchronisieren muss, also die Mutex locken/freigeben.

    EDIT: was folgt ist nur ein Vorschlag und hat nixmehr mit "so wird das 'richtig' gemacht" zu tun, nur damit das klar ist 🙂 /EDIT

    z.B. während du ein Paket empfängst musst du die Mutex ja nicht gelockt haben. Erst wenn das ganze Paket da ist lockst du die Mutex, hängst es ein eine Liste für den Hauptthread, und gibst die Mutex dann wieder frei. Im Hauptthread guckst du dann z.B. pro Frame 1x und an einer Stelle (und nicht öfter oder an verschiedenen Stellen) ob was in der Liste steht. Dazu lockst du die Mutex, guckst nach, verschiebst alles was drinnen ist in eine "private" Liste (die dem Hauptthread alleine und sonst niemandem gehört), und gibst die Mutex danach wieder frei. Dann gehst du alle Pakete in der "privaten" Liste durch, und "verteilst" sie. Sämtliche Dinge wie "Gegner erstellen" etc. machst du dann ausschliesslich im Hauptthread, NICHT im Empfangs-/Sende-Thread. Anders gesagt: die Reaktion auf empfangene Pakete erfolgt im Hauptthread.

    Wenn du Pakete verschicken willst hängst du diese einfach in eine Liste für den Sende-Thread. Es sollte reichen wenn du das ebenfalls 1x pro Frame machst, und die Pakete bis dahin irgendwo sammelst (eine 2. "private" Liste für den Hauptthread). Nachdem du die Pakete dann von der "privaten" Liste in die Liste für den Sende-Thread verschoben hast (wieder geschützt von einer Mutex, wieder nur an einer Stelle und 1x pro Frame) gibst du dem Sende-Thread nen Stoss (am einfachsten über einen EVENT, siehe CreateEvent, SetEvent, WaitForSingleObject), damit dieser wieder anläuft. Der Sende-Thread wartet eben wenn er nichts zu senden hat auf diesen "Stoss" (WaitForSingleObject), und guckt danach (wieder über Mutex geschützt) in "seiner" Liste nach, und verschiebt die Pakete da drinnen wieder in eine weitere (3.) private Liste, und fängt danach an diese zu senden. Wenn er fertig ist geht er wieder heia (WaitForSingleObject).

    Sollte alles nicht weiter dramatisch sein.

    EDIT2: guck dir evtl. an wie die RakNet das macht.



  • Hi,
    danke für die Antwort 🙂
    Das mit der Geschwindigkeit war ein anderes Problem.
    Ich hatte als Bilder im *.bmp Dateien. Ich dachte mir ich probier mal jpg um Speicher zu Sparen allerdings funktionierte da mein Color Keying nicht. Dan hab ich png Dateien genommen. dort funktionierte Color Keying wieder. Bloß komischer weise sind png Dateien sau langsam. Als ich wieder auf bmp umgestellt hatte ging alles wieder flüssig. Wieso sind png so langsam? Wie gesagt mit bmp schafft er 200 flüssig und mit png gerade mal 10!
    Mit dem Netzwerk hab ich das jetzt auch anders gemacht. Bin weg von threads und ruf jetzt jedesmal in der spielschleife einmal die funktion fürs empfangen vom Client und wenn es der Server ist auch vom Server. Da werden dann alle pakete verarbeitet bis keins mehr da ist.
    Achso und ich nutze RakNet 🙂

    schirrmie



  • Äh. Du lädst doch hoffentlich nicht für jedes Frame die Bilder neu???
    Ich meine das muss wohl so sein, denn ein *decodiertes* PNG ist "gleich schnell" wie ein *decodiertes* BMP oder sonst ein Format -- könnte also keinen Unterschied machen. Ausser natürlich du konvertierst die geladenen Bilddaten nicht ins passende Format (Pixelformat), dann würde bei jedem Blit das Pixelformat konvertiert, was natürlich langsamer ist als wenn das Pixelformat schon passt.

    Man lädt halt üblicherweise zuerst alle Bilder in verschiedene Surfaces/Texturen (plus Konvertierung ins richtige Pixelformat), und blittet die dann von dort aus in jedem Frame dahin wo man sie hinhaben will. Dann kannst du ruhig wieder PNG verwenden.

    Und wenn du schon die RakNet verwendest besteht wirklich kein Bedarf für irgendwelche Threads, da die RakNet AFAIK schon dafür sorgt dass alles im Hintergrund empfangen/übertragen wird.



  • Hi,
    Also bisher lade Ich beim Anlegen eines neuen Gegners oder was auch immer das Bild in ein Surface und bei der Show funktion zeichne ich denn alles. Wie konventiere ich denn irgendwas ins richtige Format?

    Jaja mit threads das waren die ersten überlegen das ich das mit Threads mache, habe jetzt aber gemerkt das es so ganz gut funktioniert.

    schirrmie



  • Keine Ahnung wie das in SDL geht. Vielleicht sogar automatisch -- dann könnte man ja garnix falsch machen. Ansonsten... Dokumentation lesen?




Anmelden zum Antworten