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

发布于 2024-08-13 08:12:01 字数 1006 浏览 7 评论 0原文

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

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

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

这是每个后台工作者的代码:

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
}

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

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

我不知道发生了什么。

I've gone through this SO question but 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

 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().

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());

I've no clue about whats happening.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

月野兔 2024-08-20 08:12:01

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

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

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.

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.

毁虫ゝ 2024-08-20 08:12:01

因此,您的BackgroundWorkers 似乎正在尝试同时访问相同的Windows 窗体组件。这可以解释为什么失败是随机的。

您需要使用来确保不会发生这种情况,也许像这样:

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
}

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

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

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

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.

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

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!

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.

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 post for a neat way to avoid that.

终陌 2024-08-20 08:12:01

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

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

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

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.

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.

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文