Ringpuffer im Speicher simulieren



  • Interessanterweise reicht selbst dazu EINE Critical Section:

    CRITICAL_SECTION buf_lock;
    
    int write(int value)
    {
      lock(buf_lock);
      if(wr==(rd-1)%BUFSIZE)
        error("Überlauf");
      else
      {
        buffer[wr]=value;
        wr=(wr+1)%BUFSIZE;
      }
      unlock(buf_lock);
    }
    

    Wenn mehrere Threads gleichzeitig versuchen zu lesen, blockiert der erste die CS und alle anderen warten darauf, daß er fertig wird. Schwieriger wird es erst, wenn du sicherstellen willst, daß die Threads in einer bestimmten Reihenfolge schreiben (aber dann ist Mutli-Threading vermutlich der falsche Ansatz).



  • Also die Reihenfolge ist egal, es muss nur sichergestellt werden, dass ALLE Daten abgelegt werden.. dann dürfte das ja kein Problem sein, so wie du das darstellst 😉

    Aber ich glaube, dass du noch nicht genau weißt, was ich meine.

    Ein Thread 1 ließt z.B. Daten über einen Multi I/O ein.
    Ein Thread 2 ließt z.B. Daten über einen CAN ein.
    Ein Thread 3 ...
    usw.

    Diese Daten müssen nebeneinander im Ringpuffer abgelegt werden (Ein Block im Ringpuffer besteht aus ID, Zeitstempel und Messwert). Dabei darf kein Datenblock verloren gehen. In welcher Reihenfolge diese abgespeichert werden, spielt keine Rolle.
    Gleichzeitig wird eine andere Anwendung ebenfalls auf den Ringpuffer zugreifen und diese Daten wieder auslesen und am Ende sortieren und in einer Datenbank abspeichern (das ganze wird übrigens über Shared Memory realisiert).

    Jeder Thread hat übrigens eine Cycletime, in der der Thread durchlaufen werden muss (Hardrealtime), sonst bricht das ganze System ab.

    Brauch ich dann wirklich nur eine CS?

    Wäre es sinnvoller für jeden Thread einen Ringbuffer zu machen? Wenn nicht, wie kann ich denn sicherstellen, dass alle Daten abgelegt werden?

    Danke dir schonmal.



  • CStoll schrieb:

    Interessanterweise reicht selbst dazu EINE Critical Section:

    die 'read' funktion bräuchte aber auch 'nen lock
    🙂



  • pyjamaboy schrieb:

    Also die Reihenfolge ist egal, es muss nur sichergestellt werden, dass ALLE Daten abgelegt werden.. dann dürfte das ja kein Problem sein, so wie du das darstellst 😉

    Aber ich glaube, dass du noch nicht genau weißt, was ich meine.

    Ein Thread 1 ließt z.B. Daten über einen Multi I/O ein.
    Ein Thread 2 ließt z.B. Daten über einen CAN ein.
    Ein Thread 3 ...
    usw.

    Woher jeder Thread die Daten bekommt, ist egal - am Ende der Auswertung führt er die write()-Funktion aus, um die Daten in den Ringpuffer zu packen. Und wenn gerade einer der Kollegen etwas schreiben will, ist 'buf_lock' gesperrt und er muß warten, bis der Kollege fertig ist.

    Jeder Thread hat übrigens eine Cycletime, in der der Thread durchlaufen werden muss (Hardrealtime), sonst bricht das ganze System ab.

    Wenn du die Cycletime nicht zu klein wählst, sollte das kein Problem darstellen (außer der Lese-Prozess kommt nicht mehr hinterher, den Puffer wieder aufzuräumen).

    Brauch ich dann wirklich nur eine CS?

    JA (mehrere CS wären hier eher kontraproduktiv, weil du ja nur eine Ressource (der Ringpuffer) damit schützen willst).

    Wäre es sinnvoller für jeden Thread einen Ringbuffer zu machen? Wenn nicht, wie kann ich denn sicherstellen, dass alle Daten abgelegt werden?

    Es hat beides seine Vorteile - wenn jeder Thread seinen eigenen Puffer hat, kommen sie sich nicht ins Gehege, aber die Lese-Routine wird vermutlich aufwendiger, weil sie ständig überprüfen muß, wer noch Daten hat (und bei ungünstiger Verteilung sind die Chancen höher, daß ein Thread nicht bedient wird).

    @vista: Ja, das sollte klar sein 😉



  • Okay, alles klar. Klingt soweit logisch.
    Ich habe noch nie mit CS gearbeitet, deshalb frag ich nach. Welche Libraries bzw. Header Files muss ich einbinden? Funktioniert das ganze überhaupt mit dem gcc unter Linux (ist ja ANSI C)?



  • Mit Linux kenne ich mich nicht so gut aus (ich arbeite eher mit Windows), aber das hat sicher auch Unterstützung für Threads und Critical Sections.

    (PS: Nein, "Linux" bedeutet nicht automatisch "ANSI C" - die haben genauso ihre eigenen Bibliotheken entwickelt wie die Microsoft'ler)



  • Okay, super! Danke erstmal !! 🙂



  • Es funktioniert alles soweit, bis auf eine Kleinigkeit.

    Wenn mein writeindex und mein readindex mit 0 initialisiert werden, so wird der Buffer Overflow wahrscheinlich wegen dem modulo nicht erkannt... gibts da ne schöne lösung für?



  • Was heißt "wahrscheinlich nicht erkannt"? Beim Start ist der Puffer noch leer, also gibt es auch keinen Überlauf. Und die Überprüfung in der read()-Funktion wird dir korrekt mitteilen, daß noch nichts zum Lesen da ist.



  • Also Beispiel: Es ist nur der Erzeuger da, der Daten in den Puffer (in diesem Beispiel z.B. Platz für 10 Elemente) schreibt...

    [writeindex/readindex]
    0/0
    1/0
    2/0
    3/0
    4/0
    5/0
    6/0
    7/0
    8/0
    9/0
    0/0 😉

    😉 hier müsste overflow kommen, da dieser Wert noch nicht ausgelesen wurde. kommt aber nicht!

    Hier wäre ein Leser da, der z.B. irgendwann "abstürzt"...

    [writeindex/readindex]
    0/0
    1/0
    2/0
    3/1
    4/1
    5/2
    6/2
    7/2
    8/2
    9/2
    0/2
    1/2
    2/2 **)
    ->ÜBERLAUF!

    **) Hier wird der Überlauf erkannt...

    Hier meine Ausgabe des 1. Beispiels:
    ###############################################################
    (SHM) Trying to initialize...
    (SHM) Shared Memory File (posix1) opened.
    (SHM) Size of shared memory file: 4096 bytes
    (SHM) Checking file size...
    (SHM) Now trying to map...
    (SHM) File (posix1) mapped to: 0xa0000000
    (SHM) init_shm() DONE.
    FRAME running...
    writing=5.000000 writeindex=0 readindex=0
    writing=6.000000 writeindex=1 readindex=0
    writing=8.000000 writeindex=2 readindex=0
    writing=11.000000 writeindex=3 readindex=0
    writing=15.000000 writeindex=4 readindex=0
    writing=20.000000 writeindex=5 readindex=0
    writing=26.000000 writeindex=6 readindex=0
    writing=33.000000 writeindex=7 readindex=0
    writing=41.000000 writeindex=8 readindex=0
    writing=50.000000 writeindex=9 readindex=0
    writing=60.000000 writeindex=10 readindex=0
    writing=71.000000 writeindex=11 readindex=0
    writing=83.000000 writeindex=12 readindex=0
    writing=96.000000 writeindex=13 readindex=0
    writing=110.000000 writeindex=14 readindex=0
    writing=110.000000 writeindex=0 readindex=0
    writing=111.000000 writeindex=1 readindex=0
    writing=113.000000 writeindex=2 readindex=0
    writing=116.000000 writeindex=3 readindex=0
    ###############################################################

    Hier die Ausgabe des 2. Beispiels, wenn ein Leser, die Daten ließt (siehe readindex):
    ###############################################################
    (SHM) Trying to initialize...
    (SHM) Shared Memory File (posix1) opened.
    (SHM) Size of shared memory file: 4096 bytes
    (SHM) Checking file size...
    (SHM) Now trying to map...
    (SHM) File (posix1) mapped to: 0xa0000000
    (SHM) init_shm() DONE.
    FRAME running...
    writing=5.000000 writeindex=0 readindex=0
    writing=6.000000 writeindex=1 readindex=0
    writing=8.000000 writeindex=2 readindex=1
    writing=12.000000 writeindex=3 readindex=2
    writing=18.000000 writeindex=4 readindex=3
    writing=26.000000 writeindex=5 readindex=4
    writing=36.000000 writeindex=6 readindex=5
    writing=48.000000 writeindex=7 readindex=5
    writing=61.000000 writeindex=8 readindex=5
    writing=75.000000 writeindex=9 readindex=5
    writing=90.000000 writeindex=10 readindex=5
    writing=106.000000 writeindex=11 readindex=5
    writing=123.000000 writeindex=12 readindex=5
    writing=141.000000 writeindex=13 readindex=5
    writing=160.000000 writeindex=14 readindex=5
    writing=165.000000 writeindex=0 readindex=5
    writing=171.000000 writeindex=1 readindex=5
    writing=178.000000 writeindex=2 readindex=5
    writing=186.000000 writeindex=3 readindex=5
    writing=195.000000 writeindex=4 readindex=5
    -> Error: buffer overflow (data loss).
    writing=204.000000 writeindex=4 readindex=5
    ###############################################################



  • Achso, das hatte ich nicht bedacht - versuch's mal mit "if((wr+1)%BUFSIZE==rd)", das sollte eigentlich das richtige machen.

    (verd** signed Arithmetik)



  • Danke... genau das war es! 🙂


Anmelden zum Antworten