views:

111

answers:

3

Hello,

I'm writing C# application which saves picture box screen to JPEG files.

One thread creating image:

IntPtr copyPtr = new IntPtr((void*)pArray);
image = new Bitmap(bitmapInfo.biWidth, Math.Abs(bitmapInfo.biHeight), bitmapInfo.biWidth * 3, PixelFormat.Format24bppRgb, copyPtr);
lock (image)
{
   this.CreateGraphics().DrawImage(image, (window_width - (width * new_value)) / 2, (window_height - (height * new_value)) / 2, width * new_value, height * new_value);
}

And other thread saves picture:

try
{
       while ((t < (time * 60 * 1000)) && !done)
       {
          lock (image)
          {
          image.Save(folder + this.filename + DateTime.Now.ToString("yyyMMddHHmmssFFFFFFF") + ".jpg", ImageFormat.Jpeg);
          }
          t = t + interval;
          System.Threading.Thread.Sleep(interval);
          i++;
       }
}
catch (Exception e)
{
  Console.WriteLine("Exception: " + e.Message);
  Console.WriteLine("Stack trace: " + e.StackTrace);
} 

But sometimes i get this exception:

Exception: Attempted to read or write protected memory. This is often an indicat
ion that other memory is corrupt.
Stack trace:    at System.Drawing.SafeNativeMethods.Gdip.GdipSaveImageToFile(Han
dleRef image, String filename, Guid& classId, HandleRef encoderParams)
   at System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, Encoder
Parameters encoderParams)
   at System.Drawing.Image.Save(String filename, ImageFormat format)
   at MyDLL.Window.SaveJPEG(String filename, Int32 fps, Int32
 time)

I used lock call but it seems not very helpful. I can save image in same thread. But maybe there's any solution how to solve this problem while using threads. Thanks.

+1  A: 

Check the declaration of your image variable. It is possible that you have it defined with public access. It is usually best to just define a private or local object within your code that you then lock e.g.

Object imageLock = new Object();
IntPtr copyPtr = new IntPtr((void*)pArray);
image = new Bitmap(bitmapInfo.biWidth, Math.Abs(bitmapInfo.biHeight), bitmapInfo.biWidth * 3, PixelFormat.Format24bppRgb, copyPtr);
lock (imageLock)
{
   this.CreateGraphics().DrawImage(image, (window_width - (width * new_value)) / 2, (window_height - (height * new_value)) / 2, width * new_value, height * new_value);
}

and then in your other thread code:

Object imageLock = new Object();
try
{
       while ((t < (time * 60 * 1000)) && !done)
       {
          lock (imageLock)
          {
          image.Save(folder + this.filename + DateTime.Now.ToString("yyyMMddHHmmssFFFFFFF") + ".jpg", ImageFormat.Jpeg);
          }
          t = t + interval;
          System.Threading.Thread.Sleep(interval);
          i++;
       }
}
catch (Exception e)
{
  Console.WriteLine("Exception: " + e.Message);
  Console.WriteLine("Stack trace: " + e.StackTrace);
} 
ChrisBD
Thanks, i'm checked that i defined image with public access
kesrut
A: 

Since you're creating a new image in the first thread each time, it won't be the same object that the second thread is locking on.

danbystrom
+1  A: 

According to the documentation you should define a private object to use as a lock object. This line in particular:

In general, avoid locking on a public type, or instances beyond your code's control

ie:

object lockObject = new object();
IntPtr copyPtr = new IntPtr((void*)pArray); 
image = new Bitmap(bitmapInfo.biWidth, Math.Abs(bitmapInfo.biHeight), bitmapInfo.biWidth * 3,  PixelFormat.Format24bppRgb, copyPtr); 
lock (lockObject) 
{ 
   this.CreateGraphics().DrawImage(image, (window_width - (width * new_value)) / 2, (window_height - (height * new_value)) / 2, width * new_value, height * new_value); 
} 
Phil