2010-01-26 2 views
4

각 스레드가 분석하고 일부를 변경하는 그림 상자에서 특정 비트 맵을 가져 와서이를 그림 상자에 다시 저장하는 다중 스레드 프로그램을 만들려고합니다. 공유 비트 맵 개체와 그림 상자를 다루는 지침에 lock()을 사용했지만 어떤 이유로 인해 6-10 개마다 "개체가 현재 다른 곳에서 사용 중"오류가 발생합니다.C# 이미지 병합시 스레딩 잠금 오류

 private Object locker = new Object(); 

    void doThread(Bitmap bmp2) //simplified - other references not important 
    { 
     //some code here 
     //.... 
     lock (locker) 
     { 
      Graphics gr = Graphics.FromImage(bmp2); //this is where i get the errors, they're related to bmp2 
      gr.DrawImage(bmp, new Rectangle(0, 0, 800, 600)); 
      gr.Dispose(); 

      pictureBox1.Image = bmp2; 
     } 
    } 

    void runThreads() 
    { 
     Bitmap bmp2 = new Bitmap(pictureBox1.Image); 

     Thread thread1 = new Thread(delegate() { doThread(bmp2); }); 
     Thread thread2 = new Thread(delegate() { doThread(bmp2); }); 
     Thread thread3 = new Thread(delegate() { doThread(bmp2); }); 
     Thread thread4 = new Thread(delegate() { doThread(bmp2); }); 

     thread1.Start(); 
     thread2.Start(); 
     thread3.Start(); 
     thread4.Start(); 
    } 

나는 잠금() 메소드에 찾을 수있는만큼 읽으려고했지만 그렇게 내가 잘못했을 수도 여전히 약간 불분명하다. 그래서 내 질문은, 왜 잠금 스레드가 지침을 실행하지 못하도록 방지 무엇입니까? 내가 그것을 잘못 사용한 적이 있습니까? 아니면 사용할 수있는 임시 해결책이 있습니까?

이 문제에 대한 도움을 주시면 대단히 감사하겠습니다.

+0

gr.DrawImage (bmp, new Rectangle (0, 0, 0, 0)) 줄에 "bmp"는 무엇입니까? ? 이것이 bmp2일까요? –

+0

bmp는 doThread() 함수 내에서 선언 된 비트 맵입니다. bmp의 내용을 bmp2로 복사하고 있습니다. bmp는 현재 스레드가 작업 한 비트 맵의 ​​일부를 저장합니다. – Bogdan

+0

bmp2는 자물쇠 밖에서 사용할 수 있습니까? 그렇지 않으면 어디에서 오류가 발생하는지 알 수 없습니다. –

답변

3

UI 스레드가 이미지를 사용하고 있기 때문에 오류가 발생합니다. 특히 pictureBox.Image = someImage를 설정하면 .NET Framework의 ImageAnimator 클래스가 이미지를 보면서 (예 : 애니메이션 .GIF 이미지의 경우)

한편 백그라운드 스레드가 이미지를 변경하여 WinForms 코드에서 "Object is currently use

다음 코드는 저에게 효과적입니다. 아무리 많은 스레드를 던지더라도 절대로 충돌하지 않습니다 :

lock (locker) 
{ 
    using (Graphics gr = Graphics.FromImage(bmp2)) 
    { 
     gr.DrawImage(Resources.someImage, new Rectangle(0, 0, 800, 600)); 
     pictureBox1.Invoke(new Action(() => pictureBox1.Image = bmp2)); 
    } 
} 

촬영은 작동하지 않습니다. 거기에 충분한 쓰레드를 던지면 충돌이 발생할 것입니다.

Win32에서 배경 스레드가 드로잉되는 동안 비트 맵을 그리는 것과 관련이 있다고 생각됩니다. 하나의 (UI) 스레드 읽기, 하나의 (배경) 스레드 쓰기. 그것은 문제로 이어질 수밖에 없습니다.

이와 같은 멀티 스레딩 버그를 해결하는 가장 좋은 방법은 종종 스레드 간의 데이터 공유를 중지하는 것입니다. 대신 데이터를 복제하고 각 스레드가 자체 로컬 사본을 갖도록하십시오.다음은 그 예입니다 :

lock (locker) 
{ 
    using (Graphics gr = Graphics.FromImage(bmp2)) 
    { 
     gr.DrawImage(Resources.someImage, new Rectangle(0, 0, 800, 600)); 
     var clone = bmp2.Clone() as Image; 
     pictureBox1.Invoke(new Action(() => pictureBox1.Image = clone)); 
    } 
} 
+0

하지만 pictureBox.Image는 문제가 아닙니다. 진짜 문제는 모든 스레드 4 개가 읽고 각 스레드에서 "그려진"bmp2입니다. – Bogdan

+0

아니요. 잠금과 Invoke 호출로 인해 Bmp2는 백그라운드 스레드 또는 UI 스레드 중 한 번에 1 스레드 씩 읽혀집니다. 위 코드가 효과가 있습니까? 그것은 여기서 완벽하게 작동합니다. –

+0

아, 방금 5000 개가 넘는 스레드를 던졌고 마침내 추락했습니다. 네가 옳아. 뭔가 다른 일이 벌어지고 있습니다. 내가 무엇인가를 찾을 수 있는지 알게 될 것이다. –

5

이유는 변수 pictureBox1이 GUI 스레드와 친 화성이 있기 때문입니다. 별도의 백그라운드 스레드에서 액세스하여 값을 변경할 수 없습니다. 값을 변경하려면 변수가 연결된 스레드에서 값을 변경해야합니다. 이것은 일반적으로 그렇다하더라도 시도를 .Invoke

를 통해이 대신

pictureBox1.Invoke((MethodInvoker)(() => pictureBox1.Image = bmp2)); 

을 완료 나는 값 BMP2 여러 스레드에서 사용되기 때문에 여전히 문제가 생각합니다. 변수 pictureBox1은 GUI 스레드에서이 값을 렌더링하려고 시도하는 반면 백그라운드 스레드는 그 위에 그래픽 객체를 생성합니다.

1

JaredPar에서 식별 한 크로스 스레딩 문제를 수정했습니다.

그런 다음 pictureBox1.Image를 bmp2 사본으로 설정하십시오.

Image bmp2copy = bmp2.Clone(); 
pictureBox1.Invoke((MethodInvoker)(() => pictureBox1.Image = bmp2copy)); 

잘하면 그게 효과가있어. 그렇지 않다면 사람들이 실제로 코드를 실행하고 코드를 사용하여 실행할 수 있도록 문제를 설명하는 베어 본 프로젝트를 작성하는 것에 대해 생각해보십시오. Threading issus는 머리 속에 너무 어려울 수 있습니다 ...

+0

나는 틀린 포스트를 읽었다, 이것은 결국 작동한다 보인다! 대단히 감사합니다! – Bogdan