I'm getting this error, and it looks like it's because the same Bitmap object is being accessed by different threads. However I am using locks everywhere with it.
public class MySingleInstanceClass
{
private Object locker = new Object();
private Bitmap myImage = new Bitmap(100, 100);
public Bitmap MyImage
{
get
{
lock (locker)
return myImage;
}
private set
{
lock (locker)
myImage = value;
}
}
private void Refresh()
{
lock (locker)
{
var g = Graphics.FromImage(myImage);
// do more processing
}
}
}
Class MySingleInstanceClass
will have only one instance. Calls to MyImage
and Refresh()
may come from different threads. As far as I understand, the code inside lock(locker)
will not be executed until it's finished in another thread, but I still get the error. Can anyone point a flaw in the code?
Exception looks like that:
A first chance exception of type 'System.InvalidOperationException' occurred in System.Drawing.dll
Error: Object is currently in use elsewhere.
at System.Drawing.Graphics.FromImage(Image image)
at (points to the line containing var g = Graphics.FromImage(myImage);)
the locker
object is not static; thus every new instance creates its own locker; you need to create locker
as static in order to prevent access from other threads if using multiple objects.
private static Object locker = new Object();
For single object scenario, using a non static class level variable as a locker is proper. If you are employing this scenario I feel that the implementation of Singleton has some problems.
UPDATE:
public sealed class MySingleInstanceClass
{
private static volatile MySingleInstanceClass instance;
private static object syncRoot = new Object();
private Bitmap myImage;
private MySingleInstanceClass()
{
myImage = new Bitmap(100, 100);
}
public static MySingleInstanceClass Instance
{
get
{
if (instance == null)
{
lock (syncRoot)
{
if (instance == null)
instance = new MySingleInstanceClass();
}
}
return instance;
}
}
public Bitmap MyImage
{
get
{
lock (syncRoot)
return myImage;
}
private set
{
lock (syncRoot)
myImage = value;
}
}
public void Refresh()
{
lock (syncRoot)
{
var g = Graphics.FromImage(myImage);
// do more processing
}
}
}
It doesn't matter whether the object that is locked is static or not. The problem is that the lock(locker)
inside the getter method unlocks as soon as the bitmap is returned. The returned reference to the bitmap is not protected by the lock and can be modified at the same time as a call to Refresh
occurs.
One possible solution would be to lock on the bitmap itself but that can introduce deadlocks if not done carefully.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With