InvalidOperationException when trying to access a complex object from another thread

旧时模样 提交于 2019-12-11 03:36:20

问题


After I tried lots and lots of solutions I couldn't solve this problem by any means so I started to believe that there is no solution for this problem.

I have an object that contains complex attributes. E.g: List<SomeComplexObject>. I am running a method from this class on a worker thread to keep the GUI running until the worker thread finishes. When it finishes execution, I want to use the attributes of these objects to update GUI let's say I want to use List<SomeComplexObject> looping through this list and update the GUI. But each time I try to access this list the debugger throws an InvalidOperationException: The calling thread cannot access this object because a different thread owns it.

I tried to make all attributes of this class volatile but with no hope I also used Lazy<T> class approach to solve but the same problem occurs.

Class that contain the worker function:

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
     }
 }

Thread creation in GUI class

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

When I try to access faceModuleOutput in class MainModules from GUI I got InvalidOperationException.

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

To brief this post: I want to access an object instantiated by a background thread from main thread but it throws

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

回答1:


A UI control needs to be created/modified from the GUI Thread. Doing otherwise is illegal.

It seems that the MainModuleThread is (at least) creating and modifying an Image . This should be done in the GUI Thread (the one that called RunMainModules_BtnClick)




回答2:


You cannot modify or even access pretty much anything that relates to the UI thread from another thread. This can get pretty extreme/annoying sometimes because you can't even get the value in a textbox or check if a checkbox is checked or not. If you want to perform an action on an object owned by the UI thread you need to invoke the UI thread to do it.

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



回答3:


Finally I found the solution ... Class BitmapImage is thread-affine so it can't be accessed by multiple threads you need first to make it opened for reading only closed for writing so the compiler can guarantee that no threads will modify it's content

So the solution ... :

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

class 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;
    }
}


来源:https://stackoverflow.com/questions/23975709/invalidoperationexception-when-trying-to-access-a-complex-object-from-another-th

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!