views:

128

answers:

2

Hi all,

I was just wondering, is Graphics.DrawImage() asynchronous? I'm struggling with a thread safety issue and can't figure out where the problem is.

if i use the following code in the GUI thread:

protected override void OnPaint(PaintEventArgs e)
{
   lock (_bitmapSyncRoot)
   {
      e.Graphics.DrawImage(_bitmap, _xPos, _yPos);
   }
}

And have the following code in a separate thread:

private void RedrawBitmapThread()
{
   Bitmap newBitmap = new Bitmap(_width, _height);
   // Draw bitmap //

   Bitmap oldBitmap = null;
   lock (_bitmapSyncRoot)
   {
      oldBitmap = _bitmap;
      _bitmap = newBitmap;
   }
   if (oldBitmap != null)
   {
      oldBitmap.Dispose();
   }
   Invoke(Invalidate);
}

Could that explain an accessviolation exception?

The code is running on a windows mobile 6.1 device with compact framework 3.5.

Edit:

Nevermind, it happens also when the methods get executed in the same thread..

A: 

Well, DrawImage isn't async. The framework wouldn't automatically make it async. Also, most all async operations in .NET start with 'Begin' just fyi.

I'm not sure where your error is coming from, but can you:

  • tell us what line the AccessViolationException is throw from?
  • make sure _bitmapSyncRoot is initialized?
Chad
I was aware of the 'begin' methods, but I'm pretty sure not all async methods return an IAsyncResult?To answer the questions: - It is an unmanaged exception, my app dies right on the spot and dr. watson shows an exception dialog. - Yes, I initialized the SyncRoot object
Roy
Thanks for the info. Can you explain how the various _<...>Bitmaps are being used on the UI? Maybe it is your call to oldBitmap.Dispose() that is causing the problem?Also, are you sure that OnPaint is being called from the GUI thread? You could do a InvokeRequired check to make sure in case that is the problem.
Chad
The bitmaps are items in a listview-like-control. (1 Bitmap for each item) I simplified the code here, but the idea was to make a invalidation queue for the items so a seperate thread can handle the redrawing of the items. About the onpaint: I only invoke Invalidate, so OnPaint is handled by the OS / CF.
Roy
+1  A: 

Yeah, is synchronous. But you make bigger assumptions in this code, you assuming that creating any Graphics object is thread-safe. Afaik it is on the desktop version of GDI+. It wouldn't be so likely on a limited resource OS like WM. Nothing you can lock, the one used for painting is created in code you can't touch.

Hans Passant
Exactly where am I creating an Graphics object?
Roy
In the code commented // Draw bitmap. CF creates one before calling OnPaint().
Hans Passant
True, forgot about that. The drawing all happens within the same thread, so this should not form a problem. I suppose the following should not throw any exceptions: Graphics.FromImage(...), Graphics.Draw...(...), Graphics.Dispose(). Right?
Roy
I was talking about *creating* the Graphics object, not just using it. I'd say you've proven that you cannot make this work.
Hans Passant
msdn: Graphics.FromImage Method. Creates a new Graphics from the specified Image. I was talking about creating a graphics object :)
Roy
Yes, the one thing you cannot lock to make it thread-safe.
Hans Passant