在項目裡面使用了.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的類裡面去,就可以避免上面說的安全執行緒問題。
由於我對多線程編程基本還是小白,上面的解釋是否正確、有沒有更好的解決,還希望各位指點。