0

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

KansaiRobot
  • 7,564
  • 11
  • 71
  • 150
  • Those two functions were made for Windows only. See the duplicate for how to call Unity API from another `Thread`. – Programmer Oct 13 '17 at 02:46
  • `this.transform` can only be accessed by the thread that created it. I dont know what `InvokeOnAppThread` does but even using that if the thread that invoke is called on did not create the `this.transform` object then it cannot access it. – CodingYoshi Oct 13 '17 at 02:49
  • @CodingYoshi Unfortunately InvokeOnAppThread is a poorly documented function. What you said is true (therefore option 2 does not work) but I thought that option was there for doing exactly that – KansaiRobot Oct 13 '17 at 03:13
  • @Programmer Thanks for the link. However this is not what I am asking (although it "solves" the secondary issue). My question is why InvokeOnAppThread does not work? (what does it mean it is "for windows only". – KansaiRobot Oct 13 '17 at 03:20
  • It does not solve your secondary issue, it should solve the main problem this question is being asked. Note that I saw your other question few days ago but didn't close it but this one is clearly a duplicate due to the `get_transform` error and you wanting to update something in the main thread. – Programmer Oct 13 '17 at 03:40
  • 2
    InvokeOnAppThread is used on Windows only to make Windows plugin. 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. It won't build for Android, iOS, Mac and others. Finally, `InvokeOnAppThread` is used when building a native plugin and a bridge between Windows app and Unity. That is used when you build Windows application and then want to integrate Unity into it. You can then use it to invoke functions on that Windows project thread not even on Unity Thread. – Programmer Oct 13 '17 at 03:44
  • You can read more about this [here](https://docs.unity3d.com/Manual/windowsstore-appcallbacks.html) – Programmer Oct 13 '17 at 03:47
  • How can I mark your comment as >the answer< to this question? – KansaiRobot Oct 13 '17 at 03:50
  • You can't because it is marked as a duplicate and that is a comment. I can re-open it then put that as an answer if that comment is what you are looking for. – Programmer Oct 13 '17 at 03:54
  • That is the answer to my question. InvokeOnAppThread seems to work only for Windows targets. (although I haven't managed to make it work) – KansaiRobot Oct 13 '17 at 04:03

1 Answers1

2

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.

Programmer
  • 121,791
  • 22
  • 236
  • 328