Ringpuffer im Speicher simulieren
-
Das klappt ja auch soweit (habe einen anderen Algorithmus verwendet). Aber wenn jetzt z.B. mein readindex bei 15 ist und mein Writeindex bei 4, dann soll er alle Werte von 15 bis ENDE des Puffers und von ANFANG des Puffers bis 4 auslesen... das klappt noch nicht so.
-
pyjamaboy schrieb:
Aber wenn jetzt z.B. mein readindex bei 15 ist und mein Writeindex bei 4, dann soll er alle Werte von 15 bis ENDE des Puffers und von ANFANG des Puffers bis 4 auslesen... das klappt noch nicht so.
am beispiel von CStoll's 'read' funktion musste die nur so oft aufrufen, bis sie auf den 'error' kommt, dann sind alle bytes ausgelesen (beachte das modulus '%')
-
Jup habs schon gemerkt, funzt jetzt wunderbar. Danke euch!
Wie schauts aus wegen Threadsicherheit?
-
pyjamaboy schrieb:
Wie schauts aus wegen Threadsicherheit?
So, wie's dort steht, ist sie (hm) nicht vorhanden. Aber das lässt sich recht leicht beheben, indem du noch eine Critical Section dazunimmst und beide Funktionen diese sperren, bevor sie anfangen zu arbeiten.
-
Okay, aber es kommt noch ne zusätzliche SChwierigkeit dazu:
Ich habe z.B. 5 Threads, die GLEICHZEITIG Daten einlesen. Diese Daten sollen im Ringpuffer hintereinander abgelegt werden (müssen nicht sortiert sein). Wie kann ich DAS threadsicher realisieren, ohne dass Daten überschrieben werden bzw. gemischt werden...?
-
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/0hier 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!