2009-10-12 4 views
4

Je travaille dans une API qui appelle la fonction principale via plusieurs threads. J'essaye d'accéder à travers cette fonction un Bitmap dans une autre classe et j'écris dessus, mais même après l'avoir configuré pour utiliser une instance complètement différente de l'objet, je rencontre une InvalidOperationException: la région Bitmap est déjà verrouillée.La région bitmap est déjà verrouillée, environnement multithread

J'ai essayé le code de verrouillage dans la fonction principale et où Bitmap.LockBits (...) est appelé. Oui, UnlockBits est appelé quand j'ai terminé.

/* 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

Veuillez publier un petit exemple complet illustrant le problème. –

+0

@Andrew: mes pensées exactement - la définition de "instance complètement différente" sonne clé. –

+6

Il ne peut pas être lié mais il ne me semble pas juste. Vous ne devriez pas verrouiller (typeof (ClassA)). Je verrouille normalement une variable privée. Voir ici pour plus de détails http://msdn.microsoft.com/en-us/library/c5kehkcz(v=vs.80).aspx –

Répondre

4

Le problème est très probablement que la ressource partagée - le bitmap - n'est pas protégée par le verrou dans l'exemple de code. Le verrou doit envelopper les deux appels LockBits et UnlockBits pour être efficace contre l'accès simultané à l'instance Bitmap.

Dans ce cas, je conseille d'utiliser l'instance réelle Bitmap comme objet de verrouillage car c'est ce qui doit être protégé contre l'accès simultané à partir de différents threads.

Le verrouillage typeof(ClassA) n'est recommandé que lors de l'utilisation de verrous dans des méthodes statiques.

Veuillez noter que les serrures sont des serrures à exclusion mutuelle et que les autres filetages seront suspendus alors qu'un seul filetage a été utilisé. Si la plupart du temps est passé à l'intérieur de la serrure, peu ou pas de bénéfices de parallélisation viendront de plusieurs threads.

Dans le cas d'une exception, le verrou sera libéré par la conception de la construction de verrou, tandis que la méthode UnlockBits ne sera généralement pas appelée. Si une exception peut être levée et interceptée, je vous recommande d'appeler la méthode UnlockBits à partir d'un bloc finally. Quelque chose comme ceci:

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

Cette logique peut également être enveloppé dans sa propre classe qui implémente l'interface IDisposable permettant la using puissante construction à utiliser.