2009-10-12 2 views
4

저는 다중 스레드를 통해 main 함수를 호출하는 API에서 작업하고 있습니다. 그 함수를 통해 다른 클래스의 Bitmap에 접근하여 그것으로부터 쓰기를 시도하고 있지만, 객체의 완전히 다른 인스턴스를 사용하도록 설정 한 후에도 InvalidOperationException이 발생합니다 : 비트 맵 영역이 이미 잠겨 있습니다.비트 맵 영역은 이미 잠겨져 있고 멀티 스레드 환경입니다.

주 함수에서 코드를 잠그고 Bitmap.LockBits (...)를 호출하려고했습니다. 예, UnlockBits가 끝나면 호출됩니다.

/* Part of Class B */ 
    public Surface imageSurface //Surface is a field of pixels, more or less. 
    { 
     get 
     { 
      if (_CurrImage != null && _imageSurface == null) 
      { 

       _imageSurface = Surface.CopyFromBitmap(_CurrImage); 
       return Surface.CopyFromBitmap(_imageSurface.CreateAliasedBitmap()); 
      } 
      else 
      { 
       Surface clearPixel = new Surface(1, 1); 
       clearPixel[0, 0] = ColorBgra.FromBgra(255, 255, 255, 0); 
       return clearPixel; 
      } 
     } 
    } 
    /* the "main" function, Class A */ 
    public override void Render(ClassBPrototype parameters, ...) 
    { 
     ClassB token = (ClassB)parameters; // Here we go again~! 
     ... 
     Surface ourSurface = dstArgs.Surface; 
     if (token.imageSurface.Size != null) 
     { 
      ourSurface = token.imageSurface; 
     } 

     lock(typeof(ClassA)) 
     { 
      for (int lRectangleIndex = ...) 
      { 
       Rectangle lRectangle = rois[lRectangleIndex]; 

       for (int y = ...) 
       { 
        surfaceY = (ourSurface.Height/2) - (y - (int)CenterY); 

        for (int x = ...) 
        { 
         surfaceX = (ourSurface.Width/2) - (x - (int)CenterX); 
         if (surfaceX >= 0 && surfaceX < ourSurface.Width && surfaceY >= 0 && surfaceY < ourSurface.Height) 
         { 
          dstArgs.Surface[x, y] = ourSurface[surfaceX, surfaceY]; 
         } 
         else 
         { 
          dstArgs.Surface[x, y] = ColorBgra.FromBgra(255, 255, 255, 0); 
         } 

        } 
       } 
      } 
     } 
    } 
+0

문제를 나타내는 작고 완벽한 예를 게시하십시오. –

+0

@Andrew : 내 생각은 "완전히 다른 인스턴스"의 정의가 핵심으로 들립니다. –

+6

관련성이 없지만 나에게 맞는 것은 아닙니다. 당신은 잠글해서는 안됩니다 (typeof (ClassA)). 나는 보통 개인 변수를 잠급니다. 자세한 내용은 여기를 참조하십시오. http://msdn.microsoft.com/en-us/library/c5kehkcz(v=vs.80).aspx –

답변

4

코드 예제에서 공유 리소스 인 비트 맵이 잠금으로 보호되지 않을 가능성이 높습니다. 자물쇠는 및 UnlockBits 호출을 모두 포장하여 Bitmap 인스턴스에 대한 동시 액세스를 효과적으로 차단해야합니다.

이 경우 실제로는 Bitmap 인스턴스를 잠금 개체로 사용하는 것이 좋습니다. 이는 서로 다른 스레드에서 동시에 액세스 할 필요가 있기 때문입니다.

typeof(ClassA)에서 잠그는 것은 정적 메서드 내에서 잠금을 사용할 때만 권장됩니다.

잠금은 상호 배제 잠금이며 하나의 스레드가 잠금을 획득하는 동안 다른 스레드는 일시 중단됩니다. 대부분의 시간이 잠금 장치 내부에서 소비되는 경우 다중 스레드를 사용하지 않아도 병렬화 효과가 거의 발생하지 않습니다.

예외의 경우 잠금 구성의 디자인에 의해 잠금이 해제되는 반면 UnlockBits 메서드는 일반적으로 호출되지 않습니다. 예외가 발생하여 catch 될 수있는 경우 finally 블록에서 UnlockBits 메서드를 호출하는 것이 좋습니다. 이런 식으로 뭔가 :

private Bitmap _bitmap; 
public void foo() 
{ 
    lock (_bitmap) 
    { 
     BitmapData data; 
     try 
     { 
      data = _bitmap.LockBits(area, ImageLockMOde.ReadOnly, pixelFormat); 
      UseBitmapData(data); 
     } 
     finally 
     { 
      _bitmap.UnlockBits(data); 
     } 
    } 
} 

이 논리는 또한 강력한 using 구조를 허용는 IDisposable 인터페이스를 구현하는 그것의 자신의 클래스에 싸여하여 사용할 수있다.