KansaiRobot
KansaiRobot

Reputation: 10012

InvokeOnAppThread invokes on application thread throws an error

In Unity I have the following code in a script attached to a generic Game Object that has a Cube in it:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Threading;
//using System.Runtime.Tasks;

public class ExampleScript : MonoBehaviour {

    // Use this for initialization
    void Start () 
    {
        Debug.Log ("Start():: Starting");
        //SlowJob ();

        Thread myThread = new Thread (SlowJob);

        myThread.Start ();

        Debug.Log ("Start():: Done");

    }

    // Update is called once per frame
    void Update () {

        //Option 1) This will move the cube in the application thread
        //this.transform.Translate (Vector3.up * Time.deltaTime);

    }


    void SlowJob()
    {

        Debug.Log ("ExampleScript::SlowJob() --Doing 1000 things, each taking 2ms ");

        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        sw.Start ();

        for (int i = 0; i < 1000; i++) 
        {
            //Option 2) We are trying to move the cube in the secondary thread! ooops!!
            //this.transform.Translate (Vector3.up * 0.002f);
            //get_transform can only be called from the main thread

            //Option 3) We are going to try to use a delegate on application thread 
            UnityEngine.WSA.Application.InvokeOnAppThread (()=>{
                this.transform.Translate (Vector3.up * 0.002f);
            },false);

            //Option4
/*          UnityEngine.WSA.Application.InvokeOnUIThread (()=>{
                this.transform.Translate (Vector3.up * 0.002f);
            },false);
*/
            Thread.Sleep (2);  //sleep for 2ms

        }

        sw.Stop ();

        Debug.Log ("ExampleScript::SlowJob() --Done!  Elapsed Time:" + sw.ElapsedMilliseconds / 1000f);


    }
}

As you can see there is a SlowJob function that is executing on a different thread. Now, I want to update something in unity (the cube in this case) So I tried four things:

  1. Move the cube in the main thread. This works well, as it should
  2. Move the cube from the secondary thread. This of course, does not work. The error says "get_transform can only be called from the main thread. This of course is expected.
  3. Move the cube using InvokeOnAppThread. The (scarce) documentation says that this invokes a delegate on application thread. I am thinking that this should work. But it throws the same error
  4. Just to try I also tried InvokeOnUIThread with the same error.

My question is why Option 3 does not work? I thought InvokeOnAppThread was used for these cases

(Just in case in SO there is only one other question regarding InvokeOnAppThread. Asked by me. And this is a different question so this is not a duplicate question)

My question is not on how to call unity stuff from another thread (although it solves that as well). My question is Why InvokeOnAppThread does not work for this?

I am aware there are convoluted ways to solve this. This is not what this question is about

I repeat This is not a duplicate question.

Any useful advice greatly appreciated

Upvotes: 0

Views: 1357

Answers (1)

Programmer
Programmer

Reputation: 125455

My question is why Option 3 does not work? I thought InvokeOnAppThread was used for these cases

The InvokeOnAppThread function is not used to make a call on Unity's main Thread from another Thread. It's is used to communicate between Unity and Windows App Thread. This function is used when making Windows App the native way with XAML then later decided to integrate Unity into this project. You can use it as a bridge to send message from the native side on the App main Thread to Unity or vice-versa. It's not meant to be called from another Thread created by you, like you thought and like you are currently using it.

The InvokeOnAppThread and InvokeOnUIThread functions are poorly documented but to simplify them:

InvokeOnAppThread - Used to invoke method from XAML to Unity.

InvokeOnUIThread - Used to invoke method from Unity to XAML.

This is what is used to be in the past and hopefully, it is still have way. See Ref1 and Ref2 for examples.

Also, It's from the WSA namespace and once you use it, you can't build your app for any other platform except for Windows platform. Your project won't build for Android, iOS, Mac and others.

Finally, you don't have a Windows XAML app you are communication with so you don't need InvokeOnAppThread. Again, InvokeOnAppThread is not used to communicate between your Thread and Unity's main Thread. It is used to communicate between Windows side of program made with XAML and Unity. You simply want to use Unity API in another Thread. You either have to make your own function/wrapper to do that or use the one I already made from here.

Upvotes: 2

Related Questions