c# - Use Unity API from another Thread or call a function in the main Thread -


my problem try use unity socket implement something. each time, when new message need update updattext(it unity text). however, when following code, void update not calling every time.

the reason not include updatetext.getcomponent<text>().text = "from server: "+tempmesg;in void getinformation function in thread, when include in getinformation() come error:

getcomponentfastpath can called main thread

i think problem don't know how run main thread , child thread in c# together? or there maybe other problems... hope can help.. there code:

using unityengine; using system.collections; using system; using system.net.sockets; using system.text; using system.threading; using unityengine.ui;   public class client : monobehaviour {      system.net.sockets.tcpclient clientsocket = new system.net.sockets.tcpclient();     private thread othread;  //  ui update     public gameobject updatetext;     string tempmesg = "waiting...";      // use initialization     void start () {         updatetext.getcomponent<text>().text = "waiting...";         clientsocket.connect("10.132.198.29", 8888);         othread = new thread (new threadstart (getinformation));         othread.start ();         debug.log ("running client");     }      // update called once per frame     void update () {         updatetext.getcomponent<text>().text = "from server: "+tempmesg;         debug.log (tempmesg);     }      void getinformation(){         while (true) {             try {                 networkstream networkstream = clientsocket.getstream ();                 byte[] bytesfrom = new byte[10025];                 networkstream.read (bytesfrom, 0, (int)bytesfrom.length);                 string datafromclient = system.text.encoding.ascii.getstring (bytesfrom);                 datafromclient = datafromclient.substring (0, datafromclient.indexof ("$"));                 debug.log (" >> data server - " + datafromclient);                  tempmesg = datafromclient;                  string serverresponse = "last message server" + datafromclient;                  byte[] sendbytes = encoding.ascii.getbytes (serverresponse);                 networkstream.write (sendbytes, 0, sendbytes.length);                 networkstream.flush ();                 debug.log (" >> " + serverresponse);              } catch (exception ex) {                 debug.log ("exception error:" + ex.tostring ());                 othread.abort ();                 othread.join ();             } //          thread.sleep (500);         }     } } 

unity not thread safe, decided make impossible call api thread adding mechanism throws exception when api used thread.

this question has been asked many times there have been no proper solution/answer of them. answers "use plugin" or not thread-safe. hopefully, last one.

the usual solution see on stackoverflow or unity's forum website use boolean variable let main thread know need execute code in main thread. not right not thread-safe , not give control provide function call. if have multiple threads needs notify main thread?

another solution see use coroutine instead of thread. not work. using coroutine sockets not change anything. still end freezing problems. must stick thread code or use async.

one of proper ways create collection such list. when need executed in main thread, call function stores code execute in action. copy list of action local list of action execute code local action in list clear list. prevents other threads having wait finish executing.

you need add volatile boolean notify update function there code waiting in list executed. when copying list local list, should wrapped around lock keyword prevent thread writing it.

a script performs mentioned above:

unitythread script:

#define enable_update_function_callback #define enable_lateupdate_function_callback #define enable_fixedupdate_function_callback  using system; using system.collections; using unityengine; using system.collections.generic;   public class unitythread : monobehaviour {     //our (singleton) instance     private static unitythread instance = null;       ////////////////////////////////////////////////update impl////////////////////////////////////////////////////////     //holds actions received thread. coped actioncopiedqueueupdatefunc executed there     private static list<system.action> actionqueuesupdatefunc = new list<action>();      //holds actions copied actionqueuesupdatefunc executed     list<system.action> actioncopiedqueueupdatefunc = new list<system.action>();      // used know if whe have new action function execute. prevents use of lock keyword every frame     private volatile static bool noactionqueuetoexecuteupdatefunc = true;       ////////////////////////////////////////////////lateupdate impl////////////////////////////////////////////////////////     //holds actions received thread. coped actioncopiedqueuelateupdatefunc executed there     private static list<system.action> actionqueueslateupdatefunc = new list<action>();      //holds actions copied actionqueueslateupdatefunc executed     list<system.action> actioncopiedqueuelateupdatefunc = new list<system.action>();      // used know if whe have new action function execute. prevents use of lock keyword every frame     private volatile static bool noactionqueuetoexecutelateupdatefunc = true;        ////////////////////////////////////////////////fixedupdate impl////////////////////////////////////////////////////////     //holds actions received thread. coped actioncopiedqueuefixedupdatefunc executed there     private static list<system.action> actionqueuesfixedupdatefunc = new list<action>();      //holds actions copied actionqueuesfixedupdatefunc executed     list<system.action> actioncopiedqueuefixedupdatefunc = new list<system.action>();      // used know if whe have new action function execute. prevents use of lock keyword every frame     private volatile static bool noactionqueuetoexecutefixedupdatefunc = true;       //used initialize unitythread. call once before function here     public static void initunitythread(bool visible = false)     {         if (instance != null)         {             return;         }          if (application.isplaying)         {             // add invisible game object scene             gameobject obj = new gameobject("mainthreadexecuter");             if (!visible)             {                 obj.hideflags = hideflags.hideanddontsave;             }              dontdestroyonload(obj);             instance = obj.addcomponent<unitythread>();         }     }      public void awake()     {         dontdestroyonload(gameobject);     }      //////////////////////////////////////////////coroutine impl////////////////////////////////////////////////////// #if (enable_update_function_callback)     public static void executecoroutine(ienumerator action)     {         if (instance != null)         {             executeinupdate(() => instance.startcoroutine(action));         }     }      ////////////////////////////////////////////update impl////////////////////////////////////////////////////     public static void executeinupdate(system.action action)     {         if (action == null)         {             throw new argumentnullexception("action");         }          lock (actionqueuesupdatefunc)         {             actionqueuesupdatefunc.add(action);             noactionqueuetoexecuteupdatefunc = false;         }     }      public void update()     {         if (noactionqueuetoexecuteupdatefunc)         {             return;         }          //clear old actions actioncopiedqueueupdatefunc queue         actioncopiedqueueupdatefunc.clear();         lock (actionqueuesupdatefunc)         {             //copy actionqueuesupdatefunc actioncopiedqueueupdatefunc variable             actioncopiedqueueupdatefunc.addrange(actionqueuesupdatefunc);             //now clear actionqueuesupdatefunc since we've done copying             actionqueuesupdatefunc.clear();             noactionqueuetoexecuteupdatefunc = true;         }          // loop , execute functions actioncopiedqueueupdatefunc         (int = 0; < actioncopiedqueueupdatefunc.count; i++)         {             actioncopiedqueueupdatefunc[i].invoke();         }     } #endif      ////////////////////////////////////////////lateupdate impl//////////////////////////////////////////////////// #if (enable_lateupdate_function_callback)     public static void executeinlateupdate(system.action action)     {         if (action == null)         {             throw new argumentnullexception("action");         }          lock (actionqueueslateupdatefunc)         {             actionqueueslateupdatefunc.add(action);             noactionqueuetoexecutelateupdatefunc = false;         }     }       public void lateupdate()     {         if (noactionqueuetoexecutelateupdatefunc)         {             return;         }          //clear old actions actioncopiedqueuelateupdatefunc queue         actioncopiedqueuelateupdatefunc.clear();         lock (actionqueueslateupdatefunc)         {             //copy actionqueueslateupdatefunc actioncopiedqueuelateupdatefunc variable             actioncopiedqueuelateupdatefunc.addrange(actionqueueslateupdatefunc);             //now clear actionqueueslateupdatefunc since we've done copying             actionqueueslateupdatefunc.clear();             noactionqueuetoexecutelateupdatefunc = true;         }          // loop , execute functions actioncopiedqueuelateupdatefunc         (int = 0; < actioncopiedqueuelateupdatefunc.count; i++)         {             actioncopiedqueuelateupdatefunc[i].invoke();         }     } #endif      ////////////////////////////////////////////fixedupdate impl////////////////////////////////////////////////// #if (enable_fixedupdate_function_callback)     public static void executeinfixedupdate(system.action action)     {         if (action == null)         {             throw new argumentnullexception("action");         }          lock (actionqueuesfixedupdatefunc)         {             actionqueuesfixedupdatefunc.add(action);             noactionqueuetoexecutefixedupdatefunc = false;         }     }      public void fixedupdate()     {         if (noactionqueuetoexecutefixedupdatefunc)         {             return;         }          //clear old actions actioncopiedqueuefixedupdatefunc queue         actioncopiedqueuefixedupdatefunc.clear();         lock (actionqueuesfixedupdatefunc)         {             //copy actionqueuesfixedupdatefunc actioncopiedqueuefixedupdatefunc variable             actioncopiedqueuefixedupdatefunc.addrange(actionqueuesfixedupdatefunc);             //now clear actionqueuesfixedupdatefunc since we've done copying             actionqueuesfixedupdatefunc.clear();             noactionqueuetoexecutefixedupdatefunc = true;         }          // loop , execute functions actioncopiedqueuefixedupdatefunc         (int = 0; < actioncopiedqueuefixedupdatefunc.count; i++)         {             actioncopiedqueuefixedupdatefunc[i].invoke();         }     } #endif      public void ondisable()     {         if (instance == this)         {             instance = null;         }     } } 

usage:

this implementation allows call functions in 3 used unity functions: update, lateupdate , fixedupdate functions. allows call run coroutine function in main thread. can extended able call functions in other unity callback functions such onprerender , onpostrender.

1.first, initialize awake() function.

void awake() {     unitythread.initunitythread(); } 

2.to execute code in main thread thread:

unitythread.executeinupdate(() => {     transform.rotate(new vector3(0f, 90f, 0f)); }); 

this rotate current object scipt attached to, 90 deg. can use unity api(transform.rotate) in thread.

3.to call function in main thread thread:

action rot = rotate; unitythread.executeinupdate(rot);   void rotate() {     transform.rotate(new vector3(0f, 90f, 0f)); } 

the #2 , #3 samples executes in update function.

4.to execute code in lateupdate function thread:

example of camera tracking code.

unitythread.executeinlateupdate(()=> {     //your code camera moving code }); 

5.to execute code in fixedupdate function thread:

example of when doing physics stuff such adding force rigidbody.

unitythread.executeinfixedupdate(()=> {     //your code physics code }); 

6.to start coroutine function in main thread thread:

unitythread.executecoroutine(mycoroutine());  ienumerator mycoroutine() {     debug.log("hello");     yield return new waitforseconds(2f);     debug.log("test"); } 

finally, if don't need execute in lateupdate , fixedupdate functions, should comment both lines of code below:

//#define enable_lateupdate_function_callback //#define enable_fixedupdate_function_callback 

this increase performance.


Comments

Popular posts from this blog

javascript - Create a stacked percentage column -

Optimising Firebase database by automatically overwriting data -

javascript - Angular UI-Grid customTemplate directive causing rows to load slowly/? -