title: Bitmap server concurrency error with XOR
body: <p>I am writing a server that takes updates from another server, and then allows multiple clients to connect and receive the delta.  I allow the client to ask for the delta to be XOR'd.  When XOR is turned on, I get scrambled data, implying the two bitmaps are being XOR'd incorrectly.  but if i put a 100ms delay, there is no problem.</p>
  
  <p>Receive Update Function:</p>
  
  <pre><code>while (this.updateQueue != null)
  {
      Frame update;
      if (!this.updateQueue.TryDequeue(out update))
      {
          Thread.Sleep(10);
          continue;
      }
  
      lock (this.clientFrameLock)
      {
          //For Each Client connected, if the update Area is not empty
          // Union it with the new update area
          foreach (string key in this.clientFrames.Keys)
          {
              if (this.clientFrames[key].Area.IsEmpty)
              {
                  this.clientFrames[key].Area = new Rectangle(update.Area.X, update.Area.Y, update.Area.Width, update.Area.Height);
              }
              else
              {
                  Rectangle area = Rectangle.Union(this.clientFrames[key].Area, update.Area);
                  this.clientFrames[key].Area = area;
              }
          }
          // if update from server is XOR'd, unxor and apply it to this.CurrentFrame, else just Apply
          lock (this.currentFrameLock)
          {
              if (update.Mask == Mask.MASK_XOR) this.currentFrame.Buffer.XorBitmaps(update.Buffer, update.Area);
              else this.currentFrame.Buffer.Apply(update.Buffer, update.Area);
              this.currentFrame.Sequence++;
          }
      }
      update.Dispose();
  }
  </code></pre>
  
  <p>The function the client calls to get the next frame:</p>
  
  <pre><code>public Frame GetNextUpdateFrame(Compression compression, Mask desiredMask, string uuid)
  {
      Bitmap buffer;
      Bitmap newClientBuffer;
      Bitmap lastBuffer;
      Mask actualMask = Mask.MASK_NONE;
      Rectangle rect;
      int currentFrameSequence;
      Size currentFrameResolution;
      lock (this.clientFrameLock)
      {
          lock (this.currentFrameLock)
          {
              buffer = this.currentFrame.Buffer.CopyBitmap();
              newClientBuffer = buffer.CopyBitmap();
              currentFrameSequence = this.currentFrame.Sequence;
              currentFrameResolution = this.currentFrame.Resolution;
          }
          if (!this.clientFrames.ContainsKey(uuid))
          {
             this.clientFrames.Add(uuid, new Frame(currentFrameSequence, newClientBuffer.CopyBitmap(), new Rectangle(), currentFrameResolution, Mask.MASK_NONE));
             var newClientFrame = new Frame(currentFrameSequence, newClientBuffer.CopyBitmap(), new Rectangle(0, 0, currentFrameResolution.Width, currentFrameResolution.Height), currentFrameResolution, Mask.MASK_NONE);
             buffer.Dispose();
             newClientBuffer.Dispose();
             return newClientFrame;
          }
  
          Frame lastFrame = this.clientFrames[uuid];
          rect = new Rectangle(lastFrame.Area.X, lastFrame.Area.Y, lastFrame.Area.Width, lastFrame.Area.Height);
          if (rect.Width == 0 || rect.Height == 0)
          {
              buffer.Dispose();
              newClientBuffer.Dispose();
              return null;
          }
          lastBuffer = lastFrame.Buffer.CopyBitmap();
      }
  
  
      if (desiredMask == Mask.MASK_XOR)
      {
          buffer.XorBitmaps(lastBuffer, rect, rect);
          actualMask = Mask.MASK_XOR;
      }
  
  
      Bitmap smallerBitmap = buffer.CopyBitmap(rect);
      buffer.Dispose();
      lastBuffer.Dispose();
      this.clientFrames[uuid].Dispose();
      this.clientFrames.Remove(uuid);
      this.clientFrames.Add(uuid, new Frame(currentFrameSequence, newClientBuffer, new Rectangle(), currentFrameResolution, Mask.MASK_NONE));
      return new Frame(currentFrameSequence, smallerBitmap, rect, currentFrameResolution, actualMask);
  }
  </code></pre>
  
  <p>XOR function:</p>
  
  <pre><code>internal static void XorBitmaps(this Bitmap sourceBitmap, Bitmap baseBitmap, Rectangle rect, Rectangle rectBase = default (Rectangle))
  {
      if (baseBitmap == null) return;
      if (rectBase == default(Rectangle))
      {
          rectBase = new Rectangle(0, 0, baseBitmap.Width, baseBitmap.Height);
      }
      BitmapData bmdSource = sourceBitmap.LockBits(rect, ImageLockMode.ReadWrite, sourceBitmap.PixelFormat);
      BitmapData bmdBase = baseBitmap.LockBits(rectBase, ImageLockMode.ReadOnly, baseBitmap.PixelFormat);
      unsafe
      {
          for (int y = 0; y &lt; bmdSource.Height; y++)
          {
              int* rowSource = (int*)((byte*)bmdSource.Scan0 + (y * bmdSource.Stride));
              int* rowBase = (int*)((byte*)bmdBase.Scan0 + (y * bmdBase.Stride));
              for (int x = 0; x &lt; bmdSource.Width; x++)
              {
                  rowSource[x] ^= rowBase[x];
              }
          }
      }
      baseBitmap.UnlockBits(bmdBase);
      sourceBitmap.UnlockBits(bmdSource);        
  }
  </code></pre>
  
  <p>And the CopyBitmap Functions (Using Kernal32.dll CopyMemory)</p>
  
  <pre><code>internal static Bitmap CopyBitmap(this Bitmap bitmap)
  {
  int bbp = Image.GetPixelFormatSize(bitmap.PixelFormat) / 8;
  PixelFormat pixFormat;
      if (bbp != 0) pixFormat = bitmap.PixelFormat;
      else
      {
          pixFormat = PixelFormat.Format32bppRgb;
          bbp = 4;
      }
      Bitmap newBitmap = new Bitmap(bitmap.Width, bitmap.Height, pixFormat);
      BitmapData bmpdata = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, pixFormat);
      BitmapData newBitmapData = newBitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadWrite, pixFormat);
      CopyMemory(newBitmapData.Scan0, bmpdata.Scan0, (uint)(bbp * bitmap.Height * bitmap.Width));
      bitmap.UnlockBits(bmpdata);
      newBitmap.UnlockBits(newBitmapData);
      return newBitmap;
  }
  
  internal static Bitmap CopyBitmap(this Bitmap bitmap, Rectangle bounds)
  {
      Bitmap newBitmap = new Bitmap(bounds.Width, bounds.Height, bitmap.PixelFormat);
      BitmapData bmdSrc = bitmap.LockBits(bounds, ImageLockMode.ReadOnly, bitmap.PixelFormat);
      BitmapData bmdDst = newBitmap.LockBits(new Rectangle(0, 0, bounds.Width, bounds.Height), ImageLockMode.ReadWrite, newBitmap.PixelFormat);
      unsafe
      {
          for (int y = 0; y &lt; bmdSrc.Height; y++)
          {
              IntPtr rowSrc = (IntPtr)((byte*)bmdSrc.Scan0 + (y * bmdSrc.Stride));
              IntPtr rowDst = (IntPtr)((byte*)bmdDst.Scan0 + (y * bmdDst.Stride));
              CopyMemory(rowDst, rowSrc, (uint)bmdDst.Stride);
          }
      }
      newBitmap.UnlockBits(bmdDst);
      bitmap.UnlockBits(bmdSrc);
      return newBitmap;
  }
  </code></pre>
  
  <p>I've been working on this problem for weeks, i cannot seem to figure out the problem.   Any advice could be useful</p>