【问题标题】:InvalidOperationException when trying to access a complex object from another thread尝试从另一个线程访问复杂对象时出现 InvalidOperationException
【发布时间】:2014-06-01 00:29:07
【问题描述】:

在我尝试了很多很多解决方案之后,我无论如何都无法解决这个问题,所以我开始相信这个问题没有解决方案。

我有一个包含复杂属性的对象。例如:List<SomeComplexObject>。我在一个工作线程上运行这个类的一个方法,以保持 GUI 运行,直到工作线程完成。当它完成执行时,我想使用这些对象的属性来更新 GUI 假设我想使用 List<SomeComplexObject> 循环这个列表并更新 GUI。但是每次我尝试访问这个列表时,调试器都会抛出一个InvalidOperationException:调用线程无法访问这个对象,因为不同的线程拥有它。

我试图让这个类的所有属性都可变,但我也没有希望我也使用Lazy<T> 类的方法来解决,但同样的问题发生了。

包含工作函数的类:

public class MainModules
{

    #region Attributes

    public VIDEO video; 

    public string VideoPath
    {
        get;
        set;
    }

    LowLevelModule lowLevelOutput;

    //this list that I want to use to Update GUI 
    public volatile List<FaceRecognitionModule> faceModuleOutput;

    //worker function running on different thread
     public void RunMainModules()
     {
        //some complex work to set the class attributes
     }
 }

GUI 类中的线程创建

 private void RunMainModules_BtnClick(object sender, RoutedEventArgs e)
    {
      //  MainModule = new MainModules(mainModuleObj, Inpath, lif, keyframefolderpath, trdbpath, labelspath, rrankspath, alignmatpath, 11, 10);
        this.LazyMainModule = new Lazy<MainModules>(this.InitLazyMainModule);
        MainModuleThread = new Thread(this.RunMainModules);
        MainModuleThread.Start(MainModule);

    }

    public MainModules InitLazyMainModule()
    {
        return new MainModules(mainModuleObj, Inpath, lif, keyframefolderpath, trdbpath, labelspath, rrankspath, alignmatpath, 11, 10);
    }
     public void RunMainModules(Object obj)
    {
        //MainModules mm = obj as MainModules;
        MainModules mm = LazyMainModule.Value;
        mm.RunMainModules();
        this.Dispatcher.Invoke((Action)(() =>
        {
            this.InitSpeechRec_Btn.IsEnabled = true;
        }));
    }

当我尝试从 GUI 访问 MainModules 类中的 faceModuleOutput 时,我得到了 InvalidOperationException

Image img = new Image();
//InvalidOperationException occurs here
img.Source = LazyMainModule.Value.faceModuleOutput[0].keyframes[1].keyframe;

简要介绍这篇文章: 我想从主线程访问由后台线程实例化的对象,但它抛出了

InvalidOperationException : The calling thread cannot access this object because a different thread owns it. 

【问题讨论】:

  • InvalidOperationException 的 excat 消息是什么?
  • 检查异常以获取有关正在发生的无效事情的更多详细信息
  • 调用线程无法访问该对象,因为另一个线程拥有它
  • 等等,这是您要访问的 UI 元素吗?
  • 是的,我正在尝试将从工作线程返回的对象分配给 UI 元素

标签: c# wpf multithreading backgroundworker


【解决方案1】:

需要从 GUI 线程创建/修改 UI 控件。否则是违法的。

似乎 MainModuleThread (至少)正在创建和修改 Image 。这应该在 GUI 线程中完成(调用 RunMainModules_BtnClick 的线程)

【讨论】:

  • 先生,这实际上是我所做的所有 GUI 更新代码从主线程运行,但它使用另一个线程创建的对象来执行更新
  • 是的,这是非法的。以其他方式执行此操作:GUI 线程自行执行更新。
  • 我该怎么做呢?因为用于更新 GUI 的数据来自后台工作人员
  • 这篇文章将回答你的最后一个问题:stackoverflow.com/questions/661561/…
  • 先生,这篇文章解释了如何从另一个线程更新 UI 元素,这不是我想做的。现在我在 MainThread 上,我想使用另一个线程创建的对象来更新 UI 元素
【解决方案2】:

您无法从另一个线程修改甚至访问与 UI 线程相关的任何内容。这有时会变得非常极端/烦人,因为您甚至无法在文本框中获取值或检查是否选中了复选框。如果要对 UI 线程拥有的对象执行操作,则需要调用 UI 线程来执行此操作。

UIObject.Dispatcher.Invoke(() => {
   //[Perform your action in here]
  });

【讨论】:

  • 我不是试图从另一个线程访问 UI 元素,而是试图从主线程访问另一个线程创建的对象
  • 由于类属性是在后台线程上创建的,因此发生同样的异常
【解决方案3】:

最后我找到了解决方案... BitmapImage 类是线程仿射的,因此它不能被多个线程访问,您首先需要将其打开为只读,关闭为写入,这样编译器就可以保证没有线程会修改它的内容

所以解决方案...:

 //keyframe here is a BitmapImage so on creation we must call keyframe.Freeze()
 LazyMainModule.Value.faceModuleOutput[0].keyframes[1].keyframe;

班级KeyFrame:

public class KeyFrame
{
    public volatile BitmapImage keyframe;
    public volatile List<string> personsNames;
    public volatile List<string> categories;

    public KeyFrame(BitmapImage keyframe, List<string> personsNames, List<string> categories)
    {
        this.keyframe = keyframe;
        //here we call Freeze funcition on creation to make it modifiable 
        this.keyframe.Freeze();
        this.personsNames = personsNames;
        this.categories = categories;
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-14
    • 2014-07-13
    • 2012-02-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多