我收到此错误,看起来是因为不同的线程正在访问相同的Bitmap对象。但是我随处可以使用锁。
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
}
}
}
类MySingleInstanceClass
只有一个实例。对MyImage
和Refresh()
的调用可能来自不同的主题。据我所知,lock(locker)
中的代码在另一个线程完成之前不会被执行,但我仍然得到错误。任何人都可以指出代码中的缺陷吗?
异常看起来像这样:
System.Drawing.dll中出现'System.InvalidOperationException'类型的第一次机会异常
错误:对象目前正在其他地方使用。
在System.Drawing.Graphics.FromImage(图片图片)
at(指向包含var g = Graphics.FromImage(myImage)的行;)
答案 0 :(得分:9)
locker
对象不是静态的;因此每个新实例都会创建自己的储物柜;您需要将locker
创建为静态,以防止在使用多个对象时从其他线程进行访问。
private static Object locker = new Object();
对于单个对象场景,使用非静态类级别变量作为锁定器是正确的。如果您正在使用这种情况,我觉得Singleton的实现存在一些问题。
更新:
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
}
}
}
答案 1 :(得分:5)
锁定的对象是否是静态无关紧要。问题是,只要返回位图,getter方法中的lock(locker)
就会解锁。返回的位图引用不受锁保护,可以在调用Refresh
的同时进行修改。
一种可能的解决方案是锁定位图本身,但如果不仔细,可能会引入死锁。
答案 2 :(得分:1)
在我的应用中,最佳解决方案是:
在我的应用中有:
复制几个文件添加约0,01-0,2 sek。对于每个请求,最好是所有应用程序和用户的静态锁定不等待raport生成10分钟(10个用户在同一时刻点击生成按钮)。
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();
}
答案 3 :(得分:0)
您可以在将图像发送到方法
之前克隆该图像 Image newimg = (Image)img.Clone();