2

In Unity, the thread cannot operate the object provided by UnityEngine like transform.position etc, which caused an exception that get_transform can only be called from the main thread. However, these methods can be used in some async function like BeginReceive, so is there anyone can tell me why? The async function is not thread or sth else?

I try the code below:

void Start(){
    AsyncCallback callback = new AsyncCallback (demo);
    callback.BeginInvoke (null, null, null);
}

void demo(IAsyncResult result){
    Debug.Log(Thread.CurrentThread.ManagedThreadId);
    Debug.Log(gb.transform.position.ToString());
}

It does throw an exception when I run the code on Unity Editor. However, when I run this code on an Android phone directly, it didn't throw any exception and the code was performed correctly.

The log in applogcat shows that:

Line 13497: 02-20 14:37:49.973 31027 31697 I Unity   : 3
Line 13501: 02-20 14:37:49.975 31027 31697 I Unity   : (0.0, 0.0, 0.0)

So it seems that the function runs on another thread instead of main thread, so could anyone tell me why transform works on this situation?

deadmarston
  • 79
  • 1
  • 3
  • 9
  • 1
    "in some async function like BeginReceive" There are many async functions in C#. Which one did you try it on? What are you doing that requires you to use another Thread? – Programmer Feb 16 '17 at 06:57
  • I just wonder that BeginReceive should be a thread, but I can use the methods UnityEngine provide and there is no exception. – deadmarston Feb 16 '17 at 07:09
  • BeginReceive from where? Which class? There are many of these from different C# API/classes. – Programmer Feb 16 '17 at 07:27
  • Socket from System.Net.Scokets – deadmarston Feb 16 '17 at 07:53
  • You did not include your code so I can't tell what's going on but if you see no exception, it simply means that the code is not running on another Thread. As for calling/using Unity API in another Thread, take a look this [post](http://stackoverflow.com/questions/41330771/use-unity-api-from-another-thread-or-call-a-function-in-the-main-thread/41333540#41333540). – Programmer Feb 16 '17 at 10:24
  • I attached a demo code above, could you tell me why? – deadmarston Feb 20 '17 at 00:28
  • I finally got time to test this. That code is being called on another Thread. If it is doing else different on Android then that's a bug. – Programmer Feb 21 '17 at 12:20
  • Thanks for reply, I will report it to Unity. – deadmarston Feb 21 '17 at 12:33

3 Answers3

3

Unity doesn't allow calling most API functions from threads other than the main thread, period. All of the event/message processing is actually done on the main thread.

The coroutine system based on IEnumerator is a bit of a hack and doesn't actually allow for multi-threading (keep in mind that even the .NET 4.5 async/await feature doesn't necessarily imply multithreaded execution either).

If calling the UnityEngine API works, you're on the main thread.

apk
  • 1,550
  • 1
  • 20
  • 28
  • I try to call the function `Debug.Log(Thread.CurrentThread.ManagedThreadId)` to check the thread id in both functions, and that's different. I give the demo code above, could you tell me why? – deadmarston Feb 20 '17 at 00:34
  • I could only test the code on Windows - it gives the expected result of different thread IDs and an error. – apk Feb 20 '17 at 04:43
  • I run this on my android phone and attach the log above. – deadmarston Feb 20 '17 at 06:49
3

UI APIs aren't allowed to be called from a different thread than the UI one.

This simplifies how Unity works behind the scenes and actually makes it faster.

Some async methods are dispatched using an event loop and not a different thread. Just because a method is async it doesn't mean it gets to run on a different thread.

The most obvious example of this in Unity are Coroutines. They do run async, but on the main thread. This is possible because Unity adds all of to a list and executes them every frame.

Radu Diță
  • 13,476
  • 2
  • 30
  • 34
1

You can call the Unity API from other threads, but NOT if you're running the game from within the Unity Editor. Release builds do not check which thread the call to the Unity API originated from. I assume they don't bother to avoid the performance hit.

I haven't tested this much myself though. The Unity documentation is quite clear that the API is not thread-safe. Therefore, definitely don't make any property assignments or calls that change the game state from other threads. Merely reading values might be OK, but it depends on the unknown internal caching behavior of UnityEngine, ie. hashtables/dictionaries would be bad for multi-threading.

Executor
  • 61
  • 1
  • 2