Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing System.Drawing.Bitmap from GTK# Thread throws Object Currently in use elsewhere exception

Im trying to manipulate an image using system.drawing in GTk#.I want the UI to update the image on screen as soon as the user updates a textbox.To implement this i tried using the background worker from winforms,it worked but when the textbox is updated at a higher speed the application becomes stuck with no error.

So i took a look at multithreading in GTK here http://www.mono-project.com/docs/gui/gtksharp/responsive-applications/ and created a thread .

void textboxchanged()
{
    Thread thr = new Thread (new ThreadStart (ThreadRoutine));
    thr.Start ();

  }

  static void ThreadRoutine ()
  {
        LargeComputation ();

  }

  static void LargeComputation ()
  {
    image=new Bitmap(backupimage);
   //Long image processing 
  }

It works poorly than the background worker throws up object currently in use elsewhere error here image=new Bitmap(backupimage); when the speed of entry in textbox is even a little fast.What im i doing wrong ?

Update 1 :

Im not processing the same image using 2 different threads that does 2 different operations at the same time.Im calling the thread that does the same operation before the old thread is complete.As in background worker i need a way to check if the old thread has completed working before launching the new one.So basically what im looking for is a way to check if an instance of the same thread is running.In winforms i used to do if(backgroundworker.isbusy==false) then do stuff

Update 2

Solution with performance degradation

As suggested by @voo Replacing the global bitmap helped solve the issue.What i did was instead of using global bitmap.I created a global string(filename).Now i use img=new Bitmap(filename).Tried executing fast as i can no error came up.So inorder to update the GUI i used the invoke as suggested here mono-project.com/docs/gui/gtksharp/responsive-applications/.The thing is no error comes up and image gets updated,but when the typing operation is fast enough there a wait involved. Performance got degraded.This was not the case with background worker.Is there a way to improve performance.

At end of the large image processing operation method i added this to update GUI

Gtk.Application.Invoke (delegate {

            MemoryStream istream=new MemoryStream();
            img.Save (istream, System.Drawing.Imaging.ImageFormat.Png);
            istream.Position = 0;
            workimagepixbuff = new Gdk.Pixbuf (istream);
            image1.Pixbuf = workimagepixbuff.ScaleSimple (400, 300, Gdk.InterpType.Bilinear);

        });
        // cannot directly convert Bitmap to Pixbuff,so doing this 
like image 202
techno Avatar asked Jan 06 '15 16:01

techno


1 Answers

The problem here is that you are processing an image at two places (two threads) on the same time and the image operation in .Net (GDI speaking) does not allow this. Because you did not provided very much information I'm just guessing here.

When manipulating bitmap images in GDI, there are BitmapData behind the scene that needs to be locked and unlocked. This mechanism just make the picture available in memory for read/write. But AFAIK when you lock a BitmapData that is already locked you get a similar exception : System.InvalidOperationException, Bitmap region is already locked.

To me it sounds like you are getting this kind of error, but with other words because you are not explicitly locking bitmap data bits. GDI just tell you : "I would have to lock bitmap data bits but I can't because the object is already used (locked) elsewhere."

The solution here may be to try to synchronize bitmap usage (where bits locking may be involved) between thread whenever they may occur. So you may want to use the lock keyword or a similar mechanism:

So try something that looks like the following:

private static object _imageLock = new object();
static void LargeComputation ()
  {
     lock(_imageLock)
     {
       image=new Bitmap(backupimage);
       //Long image processing ...
     }
  }

  static void AnotherImageOperationSomewhereElse()
  {
       lock(_imageLock)
       {
          //Another image processing on backupImage or something derived from it...
       }
  }
like image 128
John-Philip Avatar answered Nov 15 '22 00:11

John-Philip