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

我已经完成了这个问题,但没有帮助。

这里的情况不同。 我正在使用Backgroundworkers。 第一个backgroundworker开始对用户的图像输入进行操作并在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())中获取;

我不知道发生了什么事。

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

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

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

您需要确保使用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 } 

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

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

当您“输出”已处理的图像时,请务必小心以确保不对UI进行跨线程更新。 检查这篇文章是否有一个简洁的方法来避免这种情况。

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

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

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