【问题标题】:Locking does not prevent InvalidOperationException: Object is currently in use elsewhere锁定并不能防止 InvalidOperationException:对象当前正在其他地方使用
【发布时间】:2012-10-03 13:13:17
【问题描述】:

我的印象是lock() 会阻止多个线程同时访问一个对象。

但是,以下代码仍然经常抛出 InvalidOperationException(对象当前在别处使用):

lock (this)
{
    localCopy = (Bitmap)this.bm.Clone();
    int x, y;
    float pX = this.p.x;
    int width = localCopy.Width;
    x = (int)Math.Round((double)(pX * (float)width));
    if (x >= localCopy.Width) x = localCopy.Width - 1;
    y = (int)Math.Round((double)(this.p.y * (float)localCopy.Height));
    if (y >= localCopy.Height) y = localCopy.Height - 1;
    colourPixel = localCopy.GetPixel(x, y);
}

注意事项:

  • 我拆分了x 的计算以隔离异常的原因。它似乎来自访问位图。
  • 我尝试创建位图的本地副本,但这只会导致相同的异常。我试过Clone()ing 并创建一个新的位图。两者都不起作用。
  • 我尝试锁定this(如图所示)和位图对象。两者都不起作用。

我是否试图以不应该的方式使用lock()?我误解了它的目的吗?如何防止InvalidOperationExceptions?

【问题讨论】:

    标签: c# bitmap locking invalidoperationexception


    【解决方案1】:

    可能尝试使用一个对象来锁定而不是锁定“this”。

    类级变量

    private static object syncRoot = new Object();
    

    当你使用时

    lock (syncRoot)
    {
    ....
    }
    

    【讨论】:

    • 谢谢。我试过了,但访问 this.bm 仍然会导致 InvalidOperationException。
    • Tom,这个问题可能不是 lock 吗?我之所以问是因为 InvalidOperationException 的描述说“在调用方法失败是由无效参数以外的原因引起的情况下使用 InvalidOperationException。”而且 BitMap.Clone 确实需要几个不同的输入参数!
    • 你可能读错了。由于它说“除了无效参数之外的原因”,Bitmap.Clone() 的参数似乎无关紧要。此外,即使我使用新的Bitmap(Bitmap),也会出现此问题。
    • 是的。误读了..可能stackoverflow.com/questions/1851292/… 可能会有所启发。
    • @TomWright:如上面链接中所述,创建位图的线程将其锁定。 GDI 中的一些锁定。
    【解决方案2】:

    我最终明白了这一点。我将锁移到位图属性的 getter/setter 方法中,并实现了“深拷贝”方法以尽快释放该属性。

    private static object syncRoot = new Object();
    private Bitmap _bm;
    private Bitmap bm
    {
        get
        {
            lock (syncRoot)
                return this._bm.DeepClone();
        }
        set
        {
            lock (syncRoot)
            {
                this._bm = value.DeepClone();
            }
        }
    }
    

    DeepClone() 扩展方法抄自an answer to another question

    public static T DeepClone<T>(this T a)
    {
        using (MemoryStream stream = new MemoryStream())
        {
            BinaryFormatter formatter = new BinaryFormatter();
            formatter.Serialize(stream, a);
            stream.Position = 0;
            return (T)formatter.Deserialize(stream);
        }
    }
    

    【讨论】:

    • 很高兴看到我的那部分答案奏效了。那个深层克隆非常有用,谢谢!
    • 感谢分享解决方案。
    猜你喜欢
    • 1970-01-01
    • 2020-10-14
    • 2010-11-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多