C# InvalidOperationException - 对象当前正在其他地方使用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1851292/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-06 21:23:04  来源:igfitidea点击:

InvalidOperationException - object is currently in use elsewhere

c#.netwinformsbackgroundworker

提问by claws

I've gone through this SO questionbut it didn't help.

我已经解决了这个问题,但没有帮助。

The case here is different. I'm using Backgroundworkers. 1st backgroundworker starts operating on the image input of user and inside firstbackgroundworker_runworkercompleted() I'm using calling 3 other backgroundworkers

这里的情况不同。我正在使用后台工作者。第一个后台工作人员开始对用户的图像输入进行操作,并且在 firstbackgroundworker_runworkercompleted() 内部我正在调用其他 3 个后台工作人员

 algo1backgroundworker.RunWorkerAsync();
 algo2backgroundworker.RunWorkerAsync();
 algo3backgroundworker.RunWorkerAsync();

this is the code for each:

这是每个的代码:

algo1backgroundworker_DoWork()
{
 Image img = this.picturebox.Image;
 imgclone = img.clone();
 //operate on imgclone and output it
}

algo2backgroundworker_DoWork()
{
 Image img = this.picturebox.Image;
 imgclone = img.clone();
 //operate on imgclone and output it
}

similar operations are done in other algo*backgrougrondworker_doWork().

类似的操作在其他 algo*backgrougrondworker_doWork() 中完成。

Now SOMETIMES I'm getting "InvalidOperationException - object is currently in use elsewhere". Its very arbitrary. I somtimes get this in algo1backgroundworker_DoWork and sometimes in algo2backgroundworker_DoWork and sometimes in Application.Run(new myWindowsForm());

现在有时我会收到“InvalidOperationException - 对象当前正在其他地方使用”。它非常随意。我有时在 algo1backgroundworker_DoWork 中得到这个,有时在 algo2backgroundworker_DoWork 中得到这个,有时在 Application.Run(new myWindowsForm()); 中得到这个。

I've no clue about whats happening.

我不知道发生了什么。

采纳答案by Hans Passant

There's a lock inside GDI+ that prevents two threads from accessing a bitmap at the same time. This is not a blocking kind of lock, it is a "programmer did something wrong, I'll throw an exception" kind of lock. Your threads are bombing because you are cloning the image (== accessing a bitmap) in all threads. Your UI thread is bombing because it is trying to draw the bitmap (== accessing a bitmap) at the same time a thread is cloning it.

GDI+ 内部有一个锁,可防止两个线程同时访问位图。这不是阻塞类型的锁,而是“程序员做错了什么,我会抛出异常”类型的锁。您的线程正在爆炸,因为您正在所有线程中克隆图像(== 访问位图)。您的 UI 线程正在爆炸,因为它试图在线程克隆它的同时绘制位图(== 访问位图)。

You'll need to restrict access to the bitmap to only one thread. Clone the images in the UI thread before you start the BGWs, each BGW needs its own copy of the image. Update the PB's Image property in the RunWorkerCompleted event. You'll lose some concurrency this way but that's unavoidable.

您需要将位图的访问权限限制为只有一个线程。在启动 BGW 之前克隆 UI 线程中的图像,每个 BGW 都需要自己的图像副本。在 RunWorkerCompleted 事件中更新 PB 的 Image 属性。这样你会失去一些并发性,但这是不可避免的。

回答by Jeremy McGee

So it looks like your BackgroundWorkers are trying to access the same Windows Forms components at the same time. This would explain why the failure is random.

因此,看起来您的 BackgroundWorker 正在尝试同时访问相同的 Windows 窗体组件。这将解释为什么失败是随机的。

You'll need to make sure this doesn't happen by using a lock, perhaps like so:

您需要通过使用 a 来确保这不会发生lock,也许像这样:

private object lockObject = new object();

algo1backgroundworker_DoWork()
{
    Image imgclone;
    lock (lockObject)
    {
        Image img = this.picturebox.Image;
        imgclone = img.clone();
    }

    //operate on imgclone and output it
}

Note that I make sure that imgclone is local to this method - you definitely don't want to share it across all the methods!

请注意,我确保 imgclone 对于此方法是本地的 - 您绝对不想在所有方法中共享它!

On the other hand the same lockObject instance is used by all the methods. When a BackgroundWorker method enters its lock{}section, others that come to that point will be blocked. So it's important to make sure that the code in the locked section is fast.

另一方面,所有方法都使用相同的 lockObject 实例。当 BackgroundWorker 方法进入其lock{}部分时,其他到达该点的方法将被阻止。所以确保锁定部分中的代码是快速的很重要。

When you come to "output" your processed image, be careful too to make sure that you don't do a cross-thread update to the UI. Check this postfor a neat way to avoid that.

当您开始“输出”处理后的图像时,也要小心以确保您不会对 UI 进行跨线程更新。查看这篇文章,了解避免这种情况的巧妙方法。

回答by DW.

In windows forms not only should you only access the controls from a single thread but that thread should be the main application thread, the thread that created the control.

在 Windows 窗体中,您不仅应该只从单个线程访问控件,而且该线程应该是主应用程序线程,即创建控件的线程。

This means that in DoWork you should not access any controls (without using Control.Invoke). So here you would call RunWorkerAsync passing in your image clone. Inside the DoWork event handler, you can extract the parameter from the DoWorkEventArgs.Argument.

这意味着在 DoWork 中您不应访问任何控件(不使用 Control.Invoke)。所以在这里你会调用 RunWorkerAsync 传入你的图像克隆。在 DoWork 事件处理程序中,您可以从 DoWorkEventArgs.Argument 中提取参数。

Only the ProgressChanged and RunWorkerCompleted event handlers should interact with the GUI.

只有 ProgressChanged 和 RunWorkerCompleted 事件处理程序应该与 GUI 交互。