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
Post a Comment