2016-08-02 19 views
1

並行キューに〜300ビットマップのセットを保存しています。私はover-tcpビデオストリーミングプログラムのためにこれをやっています。サーバーが遅くなったら、受信したビットマップをこのキューに保存します(バッファリング)。私はこれをテストするために別のプロジェクトを作成しましたが、いくつか問題があります。キューからの読み取りと書き込み

書き込みスレッドが動作している間(キューに書き込む)、ピクチャボックスはキューから画像を表示していますが、多くの画像をスキップしているようです(「リスト」に追加されたばかりの画像を読み取っているようです)書き込みスレッド - FIFOの動作ではありません)。描画スレッドがピクチャボックスを終了すると、キューから読み込んだループはまだ動作していますが(ピクチャボックスがキューをブロックしているときは空ではありません)、ブロックされます。

ここでは、コードです:

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 

エラーはありませんが。私はキュー内にコピーがあるかもしれないと思います(なぜなら、画像ボックスはフリーズしているように見えるからです)。私は整数で同じコードを試して、それは完全に動作します。どうしたの?

+0

あなたが報告されていない例外を取得していることも可能です。それは多分、恐ろしいジェネリックGDIエラーが配置されているだけで3〜4のオブジェクトのように見えたり、オブジェクト – Plutonix

+0

を使い果たしたときに、いくつかの他のがスローされているので、あなたは何を意味するのですか?私はピクチャのbocイメージと1つのビットマップ( "ビット")のみを配置します。あなたはそれらを意味しますか? –

答えて

1

まず、Option Strictをオンにします。次に、別のスレッドからUIコントロールにアクセスすべきではありません。コアの問題は、実際に300 + 異なる画像をキューに入れていないことです。むしろ、コードは次の画像をと同じビットマップオブジェクトに何度も再描画します。また、無効なグラフィックスオブジェクトを使用しています。

他のものは、動作させようとする人工物かもしれませんが、表示するためにイメージを複製する理由はありません。

これは同じcrop_bitイメージを何度も繰り返し使用しています。

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) 

同じcrop_bitを使用すると、時間によってRead方法は、それが画像5に変更されたかもしれないque(4)を処理することを意味します。次に6。方法は、Writeで7です。短い遅延で、「オブジェクトは他の場所で使用されています」という例外を得ることができます。

デバッグ報告への変更は何が起こっているか、それは少し明確になります:

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

tagそれがキューに入ったとき、それに割り当てられた番号、rCountは、それが「デキュー数」または何です位置はキューにあった:

タグ13と#04
タグ16#05
タグ20#06
タグなどとして24 #08

二番目の数字が正しいですが、14日と15日画像は、画像16によってライターが終了すると、あなたがが残っている上書きされたオブジェクトことを見ることができるようにS#07
タグ28最後にロードされたイメージの多くのコピー。


は、アイテムのインデックスをマークするために使用されるタグで固定し、 Reader方法で行われ、報告 - 彼らは 出てくるとき:
' 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 

は、私がテストなどを通して、いくつかの2000+を実行してなかったのGDIオブジェクトの変更が全く見られないので、漏れていないようです。

+0

しかし、同じcrop_bitを何度も何度も使用するのは間違っていますか? (あなたのアプローチを使って、ラムが狂っても動作します)。私はEnqueueがcrop_bitのコピーを使用する方法を意味します。それは参照ではなくvalによって渡されます。私が書いたコードで動作するはずです。 –

関連する問題