2016-08-02 2 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

보고되지 않은 예외가 발생할 수 있습니다. 4 개체 중 3 개체 만 처분되고있는 것처럼 보이기 때문에 개체가 부족할 때 두려운 일반 GDI 오류 또는 기타 문제가 발생할 수 있습니다. – Plutonix

+0

무엇을 의미합니까? 나는 그림 boc 이미지와 하나의 비트 맵 ("비트") 만 처리합니다. 그걸 의미하니? –

답변

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) 

시간만큼 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)에 의해 작가가 완료되면, 당신은 남아 있습니다 덮어했다 개체를 볼 수있는 등의 # 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+를 실행하고 didn를 GDI Object가 전혀 변경되지 않으므로 누출되지 않습니다.

+0

하지만 동일한 crop_bit을 반복해서 사용하는 것에있어 잘못된 점은 무엇입니까? (당신의 접근법을 사용하면 램이 미쳐도 작동한다). Enqueue가 crop_bit 사본을 사용하는 방법입니다. 그것은 val에 의해 참조로 전달되지 않습니다. 그것은 내가 작성한 코드로 작동해야합니다. –