2

I get error like this in unity3d console:

INTERNAL_CALL_Internal_InstantiateSingle can only be called from the main thread. Constructors and field initializers will be executed from the loading thread when loading a scene. Don't use this function in the constructor or field initializers, instead move initialization code to the Awake or Start function.

What I'm trying is execute method which seems to be defined in main thread like "Instantiate()"

How can I invoke this method or call main thread to execute it?

EDIT

protected static void processCommand(String data) {
    ...
    } else if(data.StartsWith("LOGGEDIN")) {
        ...
        Vector3 pos = new Vector3(0, 1.2F, 0);
        Quaternion rot = Quaternion.identity;
        myModel = (GameObject)Instantiate(player, pos, rot);
...

and the thread is:

Thread tidListen = new Thread(new ThreadStart(ListenThread));
tidListen.Start();

private static void ListenThread() {
        while(connected) {
            int lData = myStream.Read(myBuffer, 0, client.ReceiveBufferSize);
            String myString = Encoding.ASCII.GetString(myBuffer);
            myString = myString.Substring(0, lData);
            processCommand(myString);
        }
    }

when i call processCommand i have there the method: Instantiate()

EDIT 2

I tried this also Link, when i get the ManagedThreadId from currentThread i get 1 (which seems to be main thread) but i get again the same error.

Erik Philips
  • 53,428
  • 11
  • 128
  • 150
Emrah Mehmedov
  • 1,492
  • 13
  • 28
  • 1
    can we see the code where you call Instantiate? – MBen Dec 29 '12 at 10:38
  • You want to release the processor to the main thread to that. Try thread yield: http://msdn.microsoft.com/en-us/library/system.threading.thread.yield.aspx – Afonso Tsukamoto Dec 29 '12 at 18:49
  • @AfonsoTsukamoto as i see yield is added in .net 4+ framework, im not sure if it is implemented in mono for unity3d to use but in any case do you have any example code for that? – Emrah Mehmedov Dec 29 '12 at 18:57
  • 1
    It will be easier to have your listener thread add to a queue of commands that gets cleared during Update(). I'm guessing that "loggedin" gets triggered infrequently enough that you can lock your queue w/o freezing Unity's mainthread. – Jerdak Dec 29 '12 at 19:42
  • I think the problem is you are processing the command on the main thread. Why not just run the while(connected) loop on the main thread without starting a new thread, then use a standard ThreadPool to execute processCommand() single-threaded? BTW, I don't think the line 'myString = myString.Substring(0, lData);' is doing anything. – saarp Dec 30 '12 at 19:09
  • I'm not familiar with unity3d, most of my multithreading work has been done in C and not C#. Just thought of that, the yield, because of some similar problems I've seen/dealt in Java. – Afonso Tsukamoto Dec 30 '12 at 19:40
  • @saarp if i don't start new thread main thread (GUI) is freezing. – Emrah Mehmedov Dec 31 '12 at 08:52
  • @EmrahMehmedov - Ah, did not realize a GUI is involved. Yes, then you need to run ListenThread() on a separate thread. Still think the rest of my comment stands, though - after reading the input, pass the string as an input parameter to the new thread which runs processCommand(). – saarp Dec 31 '12 at 16:47
  • Small addendum to my original comment. See [this for a breakdown](http://answers.unity3d.com/questions/180243/threading-in-unity.html) of Unity+threads. No matter what you do, Instantiate cannot be called from anything but main thread. If all you're doing is instantiating players, preload the max number of players and have your listener update some Player flag like "IsReady." It won't be atomic but that shouldn't matter. – Jerdak Jan 01 '13 at 06:14

2 Answers2

0

To Skip this i implement a queue system for my messages from server.

Emrah Mehmedov
  • 1,492
  • 13
  • 28
-3

Instantiate(), like StartCoroutine(), can only be called from objects that are in Unity's managed memory – i.e. are MonoBehaviours on in-scene GameObjects.

I believe your protected static void processCommand(String data) is unable to call GameObject.Instantiate() because processCommand() is not on an object that exists within the scene (and therefore inherits from MonoBehaviour). I think this because static methods (objects) cannot exist as an instance in-scene.

Try making an "instantiator" object that hangs out in the scene and does the Instantiate() calls for you.

cjcurrie
  • 624
  • 1
  • 4
  • 15
  • As i read in unity3d forums, unity3d framework is not thread safe, so we are not able to call unity3d methods from child threads. – Emrah Mehmedov Jan 08 '13 at 09:24
  • This is correct. Note that the threads do not operate in parallel, but are kernel-scheduled. Only objects that exist in the scene are managed from the same thread. – cjcurrie Jan 08 '13 at 17:58