对象目前在其他地方使用

Geo*_*kov 5 c# locking

我收到此错误,它看起来像是因为不同的线程正在访问相同的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
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

MySingleInstanceClass只有一个实例.呼叫MyImage并且Refresh()可能来自不同的线程.据我所知,内部代码lock(locker)在另一个线程完成之前不会被执行,但我仍然得到错误.任何人都可以指出代码中的缺陷吗?

异常看起来像这样:

System.Drawing.dll中发生了'System.InvalidOperationException'类型的第一次机会异常

错误:对象当前正在其他地方使用.

在System.Drawing.Graphics.FromImage(图片图片)

at(指向包含var g = Graphics.FromImage(myImage)的行;)

dar*_*yal 10

locker对象不是静态的; 因此每个新实例都会创建自己的储物柜; locker如果使用多个对象,则需要创建静态以防止从其他线程访问.

private static Object locker = new Object();
Run Code Online (Sandbox Code Playgroud)

对于单个对象场景,使用非静态类级别变量作为锁定器是正确的.如果您正在使用这种情况,我觉得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
        }
    }

}
Run Code Online (Sandbox Code Playgroud)


Dir*_*irk 5

锁定的对象是否是静态无关紧要.问题是,lock(locker)只要返回位图,getter方法内部就会解锁.返回的位图引用不受锁保护,可以在调用Refresh发生的同时进行修改.

一种可能的解决方案是锁定位图本身但如果不仔细完成则会引入死锁.