对象当前正在其他地方使用
本文关键字:其他 方使用 对象 | 更新日期: 2023-09-27 17:57:13
我收到此错误,看起来这是因为不同的线程正在访问相同的位图对象。但是,我在任何地方都使用锁。
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中发生了类型为"System.InvalidOperationException"的第一次机会异常.dll
错误:对象当前正在其他地方使用。
at System.Drawing.Graphics.FromImage(Image image)
at (指向包含 var g = Graphics.FromImage(myImage)的行;)
locker
对象不是静态的;因此每个新实例都会创建自己的储物柜;您需要将locker
创建为静态的,以便在使用多个对象时防止来自其他线程的访问。
private static Object locker = new Object();
对于单个对象方案,使用非静态类级别变量作为储物柜是合适的。如果您使用这种情况,我觉得单例的实现存在一些问题。
更新:
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
}
}
}
锁定的对象是否静态并不重要。问题是 getter 方法中的lock(locker)
在返回位图后立即解锁。返回的对位图的引用不受锁保护,可以在调用Refresh
的同时进行修改。
一种可能的解决方案是锁定位图本身,但如果不小心,可能会引入死锁。
在我的应用程序中,最好的解决方案是:
- 将带有文件的目录复制到另一个 TMP。 目录(具有 GUID 名称)
- 每个用户使用 TMP 文件
- 删除包含文件的 TMP 目录
在我的应用程序中有:
- 每个请求时长为 1 分钟
- 最大用户数为 120(内联网应用程序)
- 没有人愿意等待 5-10 分钟让 raport 生成
复制几个文件添加大约 0,01-0,2 瑞典克朗对于每个请求,最好是所有应用程序和用户的静态锁定不要等待 10 分钟等待 raport 生成(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();
}
映像发送到方法之前克隆该映像
Image newimg = (Image)img.Clone();