Kleiner FIFO Buffer

    • VB.NET

    Es gibt 10 Antworten in diesem Thema. Der letzte Beitrag () ist von noname.

      Kleiner FIFO Buffer

      VB.NET-Quellcode

      1. ''' <summary>
      2. ''' Ein ziemlich einfacher FIFO-Ring-Puffer der
      3. ''' als "generics" Klasse aufgebaut ist
      4. ''' VERMUTLICH threadsicher!
      5. ''' </summary>
      6. ''' <typeparam name="T"></typeparam>
      7. ''' <remarks></remarks>
      8. Public Class SimpleFIFOBuffer(Of T)
      9. Private Const INITIAL_CAPACITY As Integer = 10
      10. Private Elements(INITIAL_CAPACITY - 1) As T
      11. Private ElementLock As New Object
      12. Private PushIndex As Integer = 0
      13. Private PullIndex As Integer = -1 ' -1 = kein Element zum Lesen vorhanden
      14. ''' <summary>
      15. ''' Ermittelt die Anzahl der (gültigen) Elemente im Puffer
      16. ''' </summary>
      17. ''' <value></value>
      18. ''' <returns>Anzahl der Elemente</returns>
      19. ''' <remarks></remarks>
      20. Public ReadOnly Property Size() As Integer
      21. Get
      22. SyncLock (ElementLock)
      23. ' Die einfache Möglichkeit:
      24. If PullIndex = -1 Then Return 0
      25. ' Es gibt zwei weitere Möglichkeiten:
      26. ' ..-xx xxx+. Pull < Push => Size = Push - Pull
      27. ' xx+.. .-xxx Pull > Push => Size = Elementanzahl - Pull + Push
      28. If PullIndex < PushIndex Then Return PushIndex - PullIndex
      29. If PushIndex <= PullIndex Then Return Elements.Length - PullIndex + PushIndex
      30. End SyncLock
      31. End Get
      32. End Property
      33. ''' <summary>
      34. ''' Legt ein Element im Puffer ab. Falls der Puffer zu
      35. ''' klein ist, wird er vergrößert.
      36. ''' </summary>
      37. ''' <param name="arg"></param>
      38. ''' <remarks></remarks>
      39. Public Sub Push(ByVal arg As T)
      40. SyncLock (ElementLock)
      41. If PushIndex = PullIndex Then
      42. ' Array muss vergrößert werden
      43. ReDim Preserve Elements(Elements.Length + INITIAL_CAPACITY - 1)
      44. ' elemente umkopieren. Dazu "schneiden" wir das
      45. ' Array an der PullIndex Position auf und fügen neue elemente ein
      46. For i As Integer = Elements.Length - 1 To PullIndex + INITIAL_CAPACITY Step -1
      47. Elements(i) = Elements(i - INITIAL_CAPACITY)
      48. Next
      49. ' Elemente löschen, die eigentlich nicht gültig sind:
      50. For i As Integer = PullIndex To PullIndex + INITIAL_CAPACITY - 1
      51. Elements(i) = Nothing
      52. Next
      53. ' Leseposition um x Elemente nach "vorne" verschieben
      54. PullIndex += INITIAL_CAPACITY
      55. ElseIf PullIndex = -1 Then
      56. ' PullIndex war "ungültig", aber da wir ja jetzt einen Wert
      57. ' schreiben, könnten wir den ja auch wieder lesen
      58. PullIndex = PushIndex
      59. End If
      60. ' Element speichern und Schreibpointer um 1 erhöhen
      61. Elements(PushIndex) = arg
      62. PushIndex = (PushIndex + 1) Mod Elements.Length
      63. End SyncLock
      64. End Sub
      65. ''' <summary>
      66. ''' Liest einen Wert vom Puffer
      67. ''' </summary>
      68. ''' <returns></returns>
      69. ''' <remarks></remarks>
      70. Public Function Pull() As T
      71. SyncLock (ElementLock)
      72. ' natürlich nur wenn's Sinn macht ...
      73. If PullIndex = -1 Then Throw New Exception("Puffer ist leer!")
      74. ' Element zwischenspeichern und dann
      75. ' im Array löschen
      76. Dim tmp As T = Elements(PullIndex)
      77. Elements(PullIndex) = Nothing
      78. PullIndex = (PullIndex + 1) Mod Elements.Length
      79. If PullIndex = PushIndex Then
      80. ' Der Puffer wurde komplett geleert
      81. PullIndex = -1
      82. If Elements.Length > INITIAL_CAPACITY Then
      83. ' Wir setzen den Puffer auf die ursprüngliche
      84. ' Größe zurück
      85. ReDim Elements(INITIAL_CAPACITY - 1)
      86. End If
      87. End If
      88. Return tmp
      89. End SyncLock
      90. End Function
      91. End Class
      Da wir hier in "Source-Code Austausch" und nicht Tutorials sind, dürfte sich eine über die Kommentare im Code hinausgehende Erläuterung mE erübrigen.
      Im übrigen erlauben die Regeln zu diesem Unterforum, Fragen zum Code zu stellen. Wenn du also irgendwas nicht verstehst, darfst du ja fragen.

      PS "fifo" und "ringpuffer" kann man bei Wiki nachschlagen. Der Unterschied zum normalen Ringpuffer ist, dass meiner sich automatisch vergrößert und verkleinert. Wer das nicht will, kann den Code ja rausnehmen und stattdessen ne Exception werfen.
      Hey,

      er hat doch den Hinweis gegeben, dass Wikipedia Auskunft geben kann, falls einem die Begriffe FIFO oder Ringpuffer nichts sagen. Wenn auch eine kurze Einleitung, auch im Source-Code- Unterforum, nie schaden kann ;)

      Wikipedia hat aber ein kleines Anwendungsbeispiel, was ein Ringpuffer nach dem "First In - First Out" Prinzip bewerkstelligen kann:
      Durch Warteschlangen werden auch langsame externe Geräte, z.B. Drucker, von der Programmabarbeitung entkoppelt. Nach dem Einstellen eines Druckauftrages in die Warteschlange wird dem Programm der Auftrag als 'gedruckt' signalisiert, tatsächlich wird der Auftrag jedoch erst später bei Verfügbarkeit des Gerätes ausgeführt.
      Gruß, Manschula
      Ich finde trotzdem es sollte ein kleine Beschreibung dazu geschrieben werden. Wenn das jeder so macht das einfach nur der Code gepostet wird und jeder dann selber nochmal im Internet nachschauen muss, wozu der Code dient, finde ich etwas umständlich.
      Im Bezug auf "Sourcecode Austausch" und "Tutorial"....
      Gegen eine kleine Beschreibung ist ja nichts einzuwänden. 1-2 Zeilen reichen. Du musst es ja nicht bis aufs Details kommentieren und Beschreiben...
      wintoolz.de
      • wintoolz.KeyLocker - Programm zum sicheren Verwalten von Passwörten
      • wintoolz.CodeGallery - Datenbank für Codebeispiele veschiedener Programmiersprachen
      • wintoolz.Haushaltsbuch - Dient zum Auflisten der Aktivitäten ihrer Bankkonten

      Benutze auch du Ecosia

      1-2 Zeilen reichen

      Tja irgendwie hab ich das Problem, dass ein FIFO Buffer ja nicht grundsätzlich etwas Ultrakomplexes ist. Hatte eigentlich gedacht, dass ich hier eine Lösung für ein Problem anbiete. Dachte nicht, dass einscheinend einige Leute irgendwie ein Problem zu dieserr Lösung suchen.

      Bsp:
      Man hat 20-700 TCP-Connections (jeweils eigene Threads bzw asynchron), die Daten empfangen, die irgendwie verarbeitet werden müssen. Da evtl manchmal mehr Daten auflaufen als verarbeitet werden können, muss man die Daten natürlich in einem PUFFER zwischenspeichern. Und natürlich sollen die Daten in der Reihenfolge verarbeitet werden, in der sie empfangen wurden. Also muss es ein FIFO Buffer sein. Natürlich könnte man das ganze auch als simple SortedList (mit Timestamp als SortFeld) aufbauen. Aber da fehlt dann irgendwie der sportliche Ehrgeiz ;)
      Die Klasse Queue(Of T) ist bekannt? Die kriegt man mit ein paar ziemlich trivialen Zeilen threadsicher:

      VB.NET-Quellcode

      1. Public Class SyncQueue(Of T)
      2. Private _Q As Queue(Of T)
      3. Public Sub Enqueue(ByVal itm As T)
      4. SyncLock (_Q)
      5. _Q.Enqueue(itm)
      6. End SyncLock
      7. End Sub
      8. Public Function Dequeue() As T
      9. SyncLock (_Q)
      10. Return _Q.Dequeue
      11. End SyncLock
      12. End Function
      13. Public ReadOnly Property Count As Integer
      14. Get
      15. SyncLock (_Q)
      16. Return _Q.Count
      17. End SyncLock
      18. End Get
      19. End Property
      20. End Class

      Noch listiger, und speziell auf Threading-Szenarien ausgelegt, ist die BlockingCollection(Of T) des Frameworks4 - aber das ist keine Queue in dieser Bauform, sondern anners designed.