其实主要问题就是:不要在子线程中是用unity的对象,使用unity对象要在协程中使用,子线程完成后的回调函数要加到主线程的某个函数来处理,例如update,每帧去处理回调函数。
在项目里面使用了.NET的Async Socket代码,然后不知道什么时候起出现了这个怪异的报错:
CompareBaseObjectsInternal 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.
怪异是因为报错并没有影响程序执行,而是正确地接收了服务器返回的信息,并且通过回调正确显示出来,说明回调被执行了。但是从回调再调用一个解析器却一直不执行。是不是上面的错误导致的?
搜索百度CompareBaseObjectsInternal关键词只有8个结果,http://blog.csdn.net/jixuguo/article/details/26693977相对有些意义,但是博文为转载,后来看到原文,大致的意思是如果从子线程调用主线程的callback,需要给回调加一个interface。这个和我的情况不太一样,参考意义不大。
然后google,很不幸古大哥一直加载加载。。。于是去yahoo,居然还没有抽筋。最前面搜索出来的几篇文章就是unity论坛上的,大致看出一些眉目。
http://forum.unity3d.com/threads/comparebaseobjectsinternal-error.184069/#post-1258700
http://forum.unity3d.com/threads/comparebaseobjectsinternal-can-only-be-called-from-the-main-thread-annoying.195902/
http://forum.unity3d.com/threads/comparebaseobjectsinternal-can-only-be-called-from-the-main-thread-annoying.195902/
http://community.kii.com/t/error-comparebaseobjectsinternal-can-only-be-called-from-the-main-thread/378#!
http://answers.unity3d.com/questions/704284/comparebaseobjectsinternal-can-only-be-called-from-1.html
分析出来我的问题大概是在主线程里面注册了回调,
//注册所有事件的响应代码
NetEventManager.GetInstance().netMessageReceived_event += OnNetMessageReceived;
NetEventManager.GetInstance().gateServerConnected_event += OnGateServerConnected;
NetEventManager.GetInstance().errorMessageOccured_event += OnErrorReceived;
然后socketclient对象是异步的,所以做了多线程处理,当socketclient接收到消息时,回调了主线程的函数(继承自monobehaviour),这时候就导致了报错。上面第一篇unity论坛博文解释得比较清楚,大概就是unity对于API调用主线程做了限制:
“Unity chose to limit API calls to main-thread, to make a simple and solid threading model that everyone can understand and use.”
根据这个解释,我把上面的代码注释掉,程序就不报错了。估计这些事件响应代码要放到非monobehavior的类里面去,就可以避免上面说的线程安全问题。
由于我对多线程编程基本还是小白,上面的解释是否正确、有没有更好的解决,还希望各位指点。
原文地址:http://blog.csdn.net/silentrock/article/details/31075451