Forum: Offtopic Artikel "FIFO"


von Frank (Gast)


Lesenswert?

Hm.
Welcher Anfänger hat den Artikel "FIFO" verbrochen ?

uint8_t BufferIn(uint8_t byte)
{
  //if (buffer.write >= BUFFER_SIZE)
  //  buffer.write = 0; // erhöht sicherheit

  if ( ( buffer.write + 1 == buffer.read ) ||
       ( buffer.read == 0 && buffer.write + 1 == BUFFER_SIZE ) )
    return BUFFER_FAIL; // voll

Hoffentlich hat noch niemand diesen Unfug gelesen ?
Man stelle sich das mal vor, und setze im Geiste BUFFER_SIZE=2 und 
versuche zwei Elemente einzufügen, dann wirds offensichtlicher..
Setzen. sechs.

Und das auskommentierte: Was bitte erhöht da die Sicherheit ?
Das kaschiert allerhöchstens einen BUG der woanders gemacht wurde.
Oder soll das für den Fall da sein, daß sich die CPU aus versehen mal 
verrechnet ?

: Verschoben durch User
von Nop (Gast)


Lesenswert?

Frank schrieb:

> Man stelle sich das mal vor, und setze im Geiste BUFFER_SIZE=2 und
> versuche zwei Elemente einzufügen, dann wirds offensichtlicher..

Du willst also in einen Ringbuffer der Größe 2 zwei Elemente einfügen. 
Dann steht der Schreibindex unweigerlich auf dem Leseindex, und das ist 
die Abfrage-Bedingung für "Buffer ist leer" beim Lesen. Dir ist schon 
klar, wie ein Ringbuffer überhaupt funktioniert, oder?

> Und das auskommentierte: Was bitte erhöht da die Sicherheit ?

Das nennt man "defensive Programmierung", obwohl man in dem Fall 
natürlich besser stattdessen mit einem Fehlercode abbrechen sollte.

von Frank (Gast)


Lesenswert?

Verrate mir mal, warum man in ein Array daß zwei Elementen Platz bietet, 
keine zwei Elemente schreiben kann...??

von Frank (Gast)


Lesenswert?

...dem sprechen höchstens intellektuelle Schwierigkeiten entgegen, aber 
gewiss nicht die Logik :-)

von Nop (Gast)


Lesenswert?

Frank schrieb:
> Verrate mir mal, warum man in ein Array daß zwei Elementen Platz
> bietet, keine zwei Elemente schreiben kann...??

OK, Du weißt also, weas ein Array ist. Das ist schön. Dann befasse Dich 
auch mal damit, was ein RINGBUFFER ist und wie der funktioniert, bevor 
Du noch mehr Unsinn erzählst.

Deine Frage ist unsinnig gestellt. Die Frage ist, wieso man in einen 
Ringbuffer der Größe N nicht N Elemente schreiben kann, und den Grund 
habe ich Dir bereits in meinem Vorposting verraten.

von Nop (Gast)


Lesenswert?

und wenn Du schon von "intellektuellen Schwierigkeiten" schreibst.. ja, 
die sind auf Deiner Seite. Wegen des Dunning-Kruger-Effektes. Du hast 
dermaßen keine Ahnung, daß Du nichtmal merkst, daß Du keine hast. Sorry, 
so sieht es aus.

von Frank (Gast)


Lesenswert?

Bei einem Ringpuffer MUSS man also grundsätzlich ein Element 
verschwenden, wenn es nach dir geht.


Guck, so kann man feststellen ob im Puffer noch Platz ist:
(Ich mach mir jetzt nicht die Mühe die Namen des "Beispiels" zu 
verwenden:

int free = (head >= tail) ? (SIZE_OF_BUFFER - 1 - head + tail) : (tail - 
head - 1);

Das habe ich mir übrigens nicht selbst ausgedacht, sondern ist Standard.

Wenn free > 0 kannst du einfügen.


Und, oh Wunder, plötzlich muss man kein Element mehr verschwenden.
Es kommt vor, daß so  ein Element mehrere KB groß ist. Aber wenns nach 
Dir geht, ist man gezwungen die zu verschwenden ?

von Nop (Gast)


Lesenswert?

Frank schrieb:
> int free = (head >= tail)

Dann gehen wir das mal durch unter der Annahme SIZE_OF_BUFFER==2, und zu 
Anfang seien head und tail beide auf 0. Der Buffer sei leer. Das erste 
Einfügen ist trivial, also ist head jetzt 1.

Jetzt soll nochmal eingefügt werden.

head>=tail
1>=0 ist TRUE, also ist free damit
SIZE_OF_BUFFER - 1 - head + tail
2 - 1 - 1 + 0
0

> Wenn free > 0 kannst du einfügen

Mithin kannst Du nach dem Einfügen eines Elementes kein zweites 
einfügen.

Du bist am Zug.

Da ein Mod beschlossen hat, das zu verschieben, daß Gäste nicht mehr auf 
den Beitrag antworten können, ist die Diskussion damit für mich leider 
beendet. Vielen Dank, liebe Moderation.

von Dirk J. (dirk-cebu)


Lesenswert?

Nop schrieb:
> Da ein Mod beschlossen hat, das zu verschieben, daß Gäste nicht mehr auf
> den Beitrag antworten können, ist die Diskussion damit für mich leider
> beendet. Vielen Dank, liebe Moderation.

War sowieso überflüssig, hätte auch gleich kpl. in den Papierkorb 
verschoben werden können.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Nop schrieb:
> Da ein Mod beschlossen hat, das zu verschieben, daß Gäste nicht mehr auf
> den Beitrag antworten können, ist die Diskussion damit für mich leider
> beendet. Vielen Dank, liebe Moderation.

Es hat mit "Projekte und Code" einfach gar nichts zu tun. Da war es 
ursprünglich hingerotzt worden.

von Gustl B. (-gb-)


Lesenswert?

Wie man das in Software macht weiß ich nicht, aber in Hardware gibt es 
drei Fälle:

- Im gleichen Takt wird aus dem FIFO gelesen und geschrieben. Das ist OK 
und da kann der FIFO auch gerne voll sein.

- Es wird nur gelesen. FIFO darf nicht leer sein.

- Es wird nur geschrieben. FIFO darf nicht voll sein.

Man muss jedenfalls keinen Speicherplatz verschwenden.

von Frank K. (frank_abcdef)


Lesenswert?

Wenn hier etwas hingerotzt ist, dann der Artikel .)

Gustl, danke.

Ok, ich gebe zu, das int free... reicht nicht aus. Im Gegensatz zu 
anderen hier habe ich kein Problem damit Fehler zuzugeben :)

Aber so geht es tatsächlich, ohne ein Element zu verschwenden:


#define BUFFER_FAIL     0
#define BUFFER_SUCCESS  1

#define BUFFER_SIZE 2

struct Buffer {
  uint8_t data[BUFFER_SIZE];
  uint8_t read; // zeigt auf das Feld mit dem ältesten Inhalt
  uint8_t write;
  uint8_t count; // zähler <!--- NEU
} buffer = {{}, 0, 0};

//
// Gibt an wieviel Platz im Puffer ist
//
//
uint8_t BufferAvailable(void) {
  return BUFFER_SIZE - buffer.count;
}

//
// Stellt 1 Byte in den Ringbuffer
//
// Returns:
//     BUFFER_FAIL       der Ringbuffer ist voll. Es kann kein weiteres 
Byte gespeichert werden
//     BUFFER_SUCCESS    das Byte wurde gespeichert
//
uint8_t BufferIn(uint8_t byte)
{

  if (BufferAvailable() < 1) return BUFFER_FAIL; //Voll

  buffer.data[buffer.write] = byte;

  buffer.write++;
  if (buffer.write >= BUFFER_SIZE)
    buffer.write = 0;

  buffer.count++;

  return BUFFER_SUCCESS;
}

//
// Holt 1 Byte aus dem Ringbuffer, sofern mindestens eines abholbereit 
ist
//
// Returns:
//     BUFFER_FAIL       der Ringbuffer ist leer. Es kann kein Byte 
geliefert werden.
//     BUFFER_SUCCESS    1 Byte wurde geliefert
//
uint8_t BufferOut(uint8_t *pByte)
{
  if (buffer.count == 0)
    return BUFFER_FAIL;

  *pByte = buffer.data[buffer.read];

  buffer.read++;
  if (buffer.read >= BUFFER_SIZE)
    buffer.read = 0;

  buffer.count--;

  return BUFFER_SUCCESS;
}

Und bevor jetzt jemand schreit, daß der Zähler auch Platz braucht: 
Stimmt!
Aber Ringpuffer werden auch für größere Elemente als Bytes verwendet.

Bitte tut euch selbst den Gefallen und korrigiert den Artikel, oder fügt 
zumindest eine Info hinzu.
Vor allem dieser oben erwähnte wirklich fürchterliche Kommentar sollte 
raus.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

> Bitte tut euch selbst den Gefallen und korrigiert den Artikel, oder fügt
> zumindest eine Info hinzu. Vor allem dieser oben erwähnte wirklich
> fürchterliche Kommentar sollte raus.


Der steht im Wiki - was hindert Dich daran, das selbst in Ordnung zu 
bringen?

Du hast Deine "Kritik" in "Projekte & Code" abgesetzt, da hat sie 
schlichtweg nichts verloren. Hättest Du sie in "Smarthome" abgesetzt, 
oder in "Analoge Elektronik", sähe das nicht anders aus.

von Frank K. (frank_abcdef)


Lesenswert?

"Wiki":War mir nicht bekannt. Ich überlasse das trotzdem lieber euch.


Bitte nenne mir eine Rubrik die besser passt, dann poste ich das nächste 
mal dort. Das "Offtopic" der richtige Ort ist - darauf muss man erstmal 
kommen.

von Uhu U. (uhu)


Lesenswert?

Frank K. schrieb:
> Das "Offtopic" der richtige Ort ist

Dass man in diesem Fall dass mit Doppel-s schreibt, hättest du aber 
durchaus wissen können...

: Bearbeitet durch User
von Axel S. (a-za-z0-9)


Lesenswert?

Frank schrieb:
> Welcher Anfänger hat den Artikel "FIFO" verbrochen ?

1. du plenkst. https://de.wikipedia.org/wiki/Plenk
   Bitte stell das ab.

2. ein Wiki ist ein Wiki ist ein Wiki. Artikel werden nicht dadurch
   besser, daß jemand (s)einen Rant ins Forum kotzt, sondern dadurch
   daß sie korrigiert werden. Klick dir einen Account (hast du wohl
   mittlerweile?) und korrigiere den Artikel. Fertig.
   Damit ist allen Beteiligten besser gedient.

PS: falls es Diskussionsbedarf zu einem Artikel im Wiki gibt: dafür gibt 
es extra den Link "Diskussion" im linken Menu unter "Dieser Artikel"

: Bearbeitet durch User
von Markus M. (adrock)


Lesenswert?

...mich verstört auch die Tatsache, dass die Implementierung mit sperren 
der Interrupts empfohlen wird.

Bei geschickter Programmierung ist das überhaupt nicht notwendig, da man 
das Update der Pointer atomar mit einer Zuweisung am Ende machen kann.

Die Variante mit dem Counter ist dann allerdings nicht möglich, da die 
"++" Operation nicht zwingend atomar ist.

von Unbekannt U. (Gast)


Lesenswert?

Markus M. schrieb:
> ...mich verstört auch die Tatsache, dass die Implementierung mit sperren
> der Interrupts empfohlen wird.
>
> Bei geschickter Programmierung ist das überhaupt nicht notwendig, da man
> das Update der Pointer atomar mit einer Zuweisung am Ende machen kann.

Das will ich sehen!

von Uhu U. (uhu)


Lesenswert?

Unbekannt U. schrieb:
> Das will ich sehen!

Mit Gottvertrauen geht das ;-)

von Mw E. (Firma: fritzler-avr.de) (fritzler)


Angehängte Dateien:

Lesenswert?

Wer langeweile hat kann ja den Code hier ins wiki packen:
1
//FIFO Zustandsvariablen
2
static struct fifo_vars fifo1_tx;
3
4
//FIFO Speicherbereich
5
static char buf_fifo1_tx[FIFO_SIZE];
6
7
fifo_init(fifo1_tx, buf_fifo1_tx, FIFO_SIZE, uart_nbr, 1);

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Markus M. schrieb:
> da man das Update der Pointer atomar mit einer Zuweisung am Ende machen
> kann.

Atomare 16-Bit-Operationen auf einem 8-Bit-µC?

Das ginge allenfalls, wenn nicht mit Pointern, sondern Array-Indices 
gearbeitet würde, und diese nur 8 Bit groß sind, das Fifo also maximal 
256 Einträge enthalten dürfte.

Oder der Compiler müsste wissen, daß er die Pointer zwingend in einem 
16-Bit-Indexregister des µCs vorzuhalten hat, damit er sie atomar 
speichern kann. Welcher Compiler aber weiß etwas von atomaren 
Operationen und den interessanten Auswirkungen von Interrupts?

von Mikro 7. (mikro77)


Lesenswert?

Frank schrieb:
> Verrate mir mal, warum man in ein Array daß zwei Elementen Platz
> bietet,
> keine zwei Elemente schreiben kann...??

Aus Performancegründen wird lediglich mit Head und Tail Indizes 
gearbeiten. Dafür nimmt man gerne den einen verschwendeten Spot in Kauf. 
Siehe bspw. die Implementierung von boost::lockfree::spsc_queue.

von Markus M. (adrock)


Lesenswert?

Rufus Τ. F. schrieb:
> Markus M. schrieb:
>> da man das Update der Pointer atomar mit einer Zuweisung am Ende machen
>> kann.
>
> Atomare 16-Bit-Operationen auf einem 8-Bit-µC?
>
> Das ginge allenfalls, wenn nicht mit Pointern, sondern Array-Indices
> gearbeitet würde, und diese nur 8 Bit groß sind, das Fifo also maximal
> 256 Einträge enthalten dürfte.

Ja, genauso tut es doch der Code hier im Beispiel. Es wird uint8_t 
verwendet. Ich nahm jetzt mal diese Implementierung als Ausgangspunkt, 
auch wenn Pointer ggf. effizienter sind.

Auf einem 32 Bit Controller sollte das ja kein Problem sein.

Wenn man beim Schreiben so vorgeht:

- Wert in das aktuell referenzierte Byte im FIFO schreiben
- FIFO Schreibpointer updaten (Voraussetzung: atomar)

Und beim Lesen so:

- Wert aus dem aktuell refrenzierten Byte aus dem FIFO lesen
- FIFO Lesepointer updaten (Voraussetzung: atomar)

Müssen KEINE Interrupts gesperrt werden.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.