2016-08-02 6 views
1

Ich speichere eine Reihe von ~ 300 Bitmaps in einer gleichzeitigen Warteschlange. Ich mache das für ein Over-TCP-Video-Streaming-Programm. Wenn der Server langsamer wird, speichere ich die empfangenen Bitmaps in dieser Warteschlange (Pufferung). Ich habe ein separates Projekt erstellt, um das zu testen, aber ich habe einige Probleme.Lesen und Schreiben aus der Warteschlange

Während der Schreib-Thread funktioniert (Schreiben in die Warteschlange), zeigt das Bildfenster die Bilder aus der Warteschlange, aber es scheint, dass es viele von ihnen überspringt (es ist so, als lese es gerade in der "Liste" durch den Schreib-Thread-nicht-FIFO-Verhalten). Wenn der Schreib-Thread die Bildbox beendet, blockiert er, obwohl die Schleife, in der ich aus der Warteschlange lese, immer noch arbeitet (wenn die Bildbox die Warteschlange blockiert, ist sie nicht leer).

Hier ist der Code:

Imports System 
Imports System.Drawing 
Imports System.IO 
Imports System.Threading 
Imports System.Collections.Concurrent 

Public Class Form1 
    Dim writeth As New Thread(AddressOf write), readth As New Thread(AddressOf read) 
    Dim que As New ConcurrentQueue(Of Bitmap), finished As Boolean 


    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load 

    End Sub 

    Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click 
     'Start button 

     writeth.Start() 
     readth.Start()  
    End Sub 

    Sub draw(ByRef pic As Bitmap) 
     If PictureBox1.Image IsNot Nothing Then 
      PictureBox1.Image.Dispose() 
      PictureBox1.Image = Nothing 
     End If 

     PictureBox1.Image = pic 
    End Sub 

    Sub read() 
     Dim bit As Bitmap 
     While (Not finished Or Not que.IsEmpty) 
      If que.TryDequeue(bit) Then 
       draw(bit.Clone) 

       'Still working after the writing stopped 
       If finished Then Debug.Print("picture:" & que.Count) 

       Thread.Sleep(2000) 'Simulates the slow-down of the server 
      End If 
     End While 
    End Sub 

    Sub write() 
     Dim count As Integer = 0 
     Dim crop_bit As New Bitmap(320, 240), bit As Bitmap 
     Dim g As Graphics = Graphics.FromImage(crop_bit) 

     For Each fil As String In Directory.GetFiles(Application.StartupPath & "/pictures") 
      count += 1 
      Debug.Print(count) 

      bit = Image.FromFile(fil) 
      g.DrawImage(bit, 0, 0, 320, 240) 

      que.Enqueue(crop_bit) 
      bit.Dispose() 
     Next 
     finished = True 
     'At this point the picture box freezes but the reading loop still works 
    End Sub 
End Class 

kein Fehler ist. Ich denke, dass es möglicherweise Kopien in der Warteschlange gibt (weil das Bildfeld einzufrieren scheint)? Ich habe den gleichen Code mit ganzen Zahlen ausprobiert und es funktioniert perfekt. Was ist das Problem?

+0

Es ist möglich, dass Sie eine nicht gemeldete Ausnahme erhalten. Da es aussieht, als ob nur 3 von 4 Objekten entsorgt werden, wird vielleicht der gefürchtete Generic GDI Fehler oder etwas anderes geworfen, wenn Ihnen die Objekte ausgehen – Plutonix

+0

Was meinst du? Ich entsorge nur das Bild Boc-Bild und eine Bitmap ("Bit"). Meinst du das? –

Antwort

1

Schalten Sie zuerst Option Strict ein. Zweitens sollten Sie nicht auf Benutzeroberflächensteuerelemente von einem anderen Thread zugreifen. Das Kernproblem ist, dass Sie nicht wirklich 300+ verschiedene Bilder in der que setzen. Stattdessen zeichnet der Code das nächste Bild immer wieder zum selben Bitmap-Objekt. Sie verwenden auch ein möglicherweise veraltetes Grafikobjekt.

Einige andere Dinge könnten Artefakte sein, die versuchen, es zum Laufen zu bringen, aber es gibt keinen Grund, das Bild für die Anzeige zu klonen - es ergibt nur noch eine Sache, über die man verfügen muss.

Dies ist die gleiche crop_bit Bild immer und immer wieder.

Sub write() 
    Dim count As Integer = 0 
    Dim crop_bit As New Bitmap(320, 240), bit As Bitmap 
    Dim g As Graphics = Graphics.FromImage(crop_bit) 
    ... 
    que.Enqueue(crop_bit) 

die gleichen crop_bit Verwendung bedeutet, dass 5 von Zeit zu Bild der Read Verfahren verarbeitet que(4) es geändert worden sein könnte; dann 6; dann 7 nach der Write Methode. Mit einer kurzen Verzögerung konnte ich "Object is use woandy" -Ausnahmen bekommen.

Eine Änderung der Debug-Berichterstattung macht es ein wenig klarer, was los ist:

' in "read" 
Console.WriteLine("tag {0:00} as # {1:00}", 
     bit.Tag.ToString, rCount) 

tag ist die Nummer zugewiesen, wenn es in die Warteschlange ging, rCount ist es „Dequeue count“ oder was Stellung war es in der Warteschlange:

Tag 13 als 04 #
Tag 16 als 05 #
Tag 20 als # 06
Tag 24 a s # 07
Tag 28 als # 08

Die zweite Zahl ist richtig, aber man kann sehen, dass das 14. und 15. Bildobjekte 16 von Bild überschrieben wurden Wenn der Schreiber beendet ist, werden Sie nach links mit viele Kopien des zuletzt geladenen Bildes.


mit dem Tag Fest verwendet, um den Artikel Index zu markieren und in der Reader Methode getan Berichterstattung - wenn sie kommen aus:

' for picture box display 
Private DisplayImg As Action(Of Bitmap) 
... 
' initialize when you start the work: 
DisplayImg = AddressOf Display 

Sub Reader() 
    Dim bit As Bitmap = Nothing 
    Do 
     If que.TryDequeue(bit) Then 
      ' do not acccess the UI from a different thread 
      ' we know we are on a diff thread, just Invoke 
      pbImg.Invoke(DisplayImg, bit) 

      ' report on the item 
      Console.WriteLine(bit.Tag.ToString) 
      Thread.Sleep(100) 'Simulates the slow-down of the server 
     End If 
    Loop Until (finished AndAlso que.IsEmpty) 
End Sub 

Sub Writer() 
    Dim count As Integer = 0 
    Dim crop_bit As Bitmap 

    ' enumerate files is more efficient - loads one at a time 
    For Each fil As String In Directory.EnumerateFiles(filepath, "*.jpg") 
     count += 1 
     ' need a NEW bitmap for each file 
     crop_bit = New Bitmap(320, 240) 

     ' need to use and dispose of NEW graphics for each 
     ' use a NEW img from file and dispose of it 
     Using g As Graphics = Graphics.FromImage(crop_bit), 
      img = Image.FromFile(fil) 
      g.DrawImage(img, 0, 0, 320, 240) 
     End Using 
     ' put a collar on them 
     crop_bit.Tag = count.ToString 
     que.Enqueue(crop_bit) 
    Next 
    finished = True 
End Sub 

Sub Display(pic As Bitmap) 
    '... the same, 
    ' handles the display AND disposal 
    ... 
End Sub 

ich einige lief als Test 2000+ durch und didn Ich sehe GDI Object überhaupt nicht ändern, also scheint es nicht zu lecken.

+0

Aber was ist falsch daran, immer dasselbe crop_bit zu verwenden? (mit Ihrem Ansatz funktioniert es, obwohl der Widder verrückt wird). Ich meine die Methode Enqueue verwendet eine Kopie von crop_bit. Es wird von val nicht durch Verweis übergeben. Es sollte mit dem Code funktionieren, den ich geschrieben habe. –

Verwandte Themen