Reputation: 3915
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);)
Upvotes: 5
Views: 21644
Reputation: 3121
In my app the best solution was:
In my app there is:
Copy few files add about 0,01-0,2 sek. for each request, is better that static lock on all app and user don't neet to wait 10 min for raport to generate (10 users click generate button in same moment).
private void DirectoryCopy(string sourceDirName, string destDirName, bool copySubDirs)
{
// Get the subdirectories for the specified directory.
DirectoryInfo dir = new DirectoryInfo(sourceDirName);
DirectoryInfo[] dirs = dir.GetDirectories();
if (!dir.Exists)
{
throw new DirectoryNotFoundException(
"Source directory does not exist or could not be found: "
+ sourceDirName);
}
// If the destination directory doesn't exist, create it.
if (!Directory.Exists(destDirName))
{
Directory.CreateDirectory(destDirName);
}
// Get the files in the directory and copy them to the new location.
FileInfo[] files = dir.GetFiles();
foreach (FileInfo file in files)
{
string temppath = Path.Combine(destDirName, file.Name);
file.CopyTo(temppath, false);
}
// If copying subdirectories, copy them and their contents to new location.
if (copySubDirs)
{
foreach (DirectoryInfo subdir in dirs)
{
string temppath = Path.Combine(destDirName, subdir.Name);
DirectoryCopy(subdir.FullName, temppath, copySubDirs);
}
}
}
private void DeleteReportExecutionDirectory(string dirPath)
{
System.IO.DirectoryInfo downloadedMessageInfo = new DirectoryInfo(dirPath);
foreach (FileInfo file in downloadedMessageInfo.GetFiles())
{
file.Delete();
}
foreach (DirectoryInfo dir in downloadedMessageInfo.GetDirectories())
{
dir.Delete(true);
}
downloadedMessageInfo.Delete();
}
Upvotes: 1
Reputation: 717
you can clone that image before send it to method
Image newimg = (Image)img.Clone();
Upvotes: 0
Reputation: 14929
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
}
}
}
Upvotes: 11
Reputation: 10968
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.
Upvotes: 5