电影网站建设之苹果cms程序/微信朋友圈推广软文
Unity的Socket网络编程中,为了防止程序卡死,一般使用多线程来监听端口,当收到来自客户端的消息时,需要显示在界面上。但是如果直接在子线程中操作Unity的界面或物体会报错。国外一个大神写了一个UnityThread类很好地解决了这个问题。
紫色文字为谷歌翻译后的原文,个别地方作了修改。
Unity是Thread不安全的,因此他们决定Thread通过添加一种机制在从另一个人使用其API时引发异常来使其无法从另一个人调用API Thread。
这个问题已经被问了很多遍了,但是没有一个合适的解决方案/答案。答案通常是“使用插件”或执行某些不是线程安全的操作。希望这将是最后一个。
您通常会在Stackoverflow或Unity论坛网站上看到的解决方案是简单地使用一个boolean变量让主线程知道您需要在main中执行代码Thread。这是不正确的,因为它不是线程安全的,并且无法控制您提供要调用的函数。如果您有多个Threads需要通知主线程怎么办?
您将看到的另一种解决方案是使用协程而不是Thread。这并不能正常工作。对套接字使用协程不会更改任何内容。您仍然会遇到冻结问题。您必须坚持自己的Thread代码或使用Async。
执行此操作的正确方法之一是创建一个集合,例如List。当您需要在主线程中执行某些操作时,调用一个函数,该函数存储要在中执行的代码Action。复制List的Action到本地List的Action,然后从本地执行的代码Action在List随后清除List。这样可以避免其他人Threads等待它完成执行。
您还需要添加一个,volatile boolean以通知Update函数中有等待List执行的代码。将拷贝List到localList时,应将其包装在lock关键字周围,以防止另一个线程对其进行写入。
UnityThread用法:
这种实现允许你调用的函数3个最常用的统一功能:Update,LateUpdate和FixedUpdate功能。这也允许您在主线程中调用运行协程函数。它可以扩展为能够调用其他Unity回调函数中的函数,例如OnPreRender和OnPostRender。
1。首先,通过Awake()函数对其进行初始化。
void Awake()
{UnityThread.initUnityThread();
}
2。在子线程中执行主线程中Update函数的代码,请执行以下操作:
UnityThread.executeInUpdate(() =>
{transform.Rotate(new Vector3(0f, 90f, 0f));
});
这会将scipt所连接的当前对象旋转到90度。您现在可以transform.Rotate在另一个中使用Unity API()Thread。
3。在子线程中执行主线程中一个函数,请执行以下操作:
Action rot = Rotate;
UnityThread.executeInUpdate(rot);void Rotate()
{transform.Rotate(new Vector3(0f, 90f, 0f));
}
在#2和#3样品执行在Update功能。
4。在子线程中执行主线程中LateUpdate函数的代码,请执行以下操作:
这样的示例是摄像机跟踪代码。
UnityThread.executeInLateUpdate(()=>
{//Your code camera moving code
});
5。在子线程中执行主线程中FixedUpdate函数的代码,请执行以下操作:
进行物理处理(例如施加力)时的这样的例子Rigidbody。
UnityThread.executeInFixedUpdate(()=>
{//Your code physics code
});
6。在子线程中启动主线程协程函数:
UnityThread.executeCoroutine(myCoroutine());IEnumerator myCoroutine()
{Debug.Log("Hello");yield return new WaitForSeconds(2f);Debug.Log("Test");
}
最后,如果您不需要在LateUpdate和FixedUpdate函数中执行任何操作,则应在下面的代码两行中进行注释:
//#define ENABLE_LATEUPDATE_FUNCTION_CALLBACK
//#define ENABLE_FIXEDUPDATE_FUNCTION_CALLBACK
这将提高性能。
UnityThread 脚本:
#define ENABLE_UPDATE_FUNCTION_CALLBACK
#define ENABLE_LATEUPDATE_FUNCTION_CALLBACK
#define ENABLE_FIXEDUPDATE_FUNCTION_CALLBACKusing System;
using System.Collections;
using UnityEngine;
using System.Collections.Generic;public class UnityThread : MonoBehaviour
{//our (singleton) instanceprivate static UnityThread instance = null;//UPDATE IMPL//Holds actions received from another Thread. Will be coped to actionCopiedQueueUpdateFunc then executed from thereprivate static List<System.Action> actionQueuesUpdateFunc = new List<Action>();//holds Actions copied from actionQueuesUpdateFunc to be executedList<System.Action> actionCopiedQueueUpdateFunc = new List<System.Action>();// Used to know if whe have new Action function to execute. This prevents the use of the lock keyword every frameprivate volatile static bool noActionQueueToExecuteUpdateFunc = true;//LATEUPDATE IMPL//Holds actions received from another Thread. Will be coped to actionCopiedQueueLateUpdateFunc then executed from thereprivate static List<System.Action> actionQueuesLateUpdateFunc = new List<Action>();//holds Actions copied from actionQueuesLateUpdateFunc to be executedList<System.Action> actionCopiedQueueLateUpdateFunc = new List<System.Action>();// Used to know if whe have new Action function to execute. This prevents the use of the lock keyword every frameprivate volatile static bool noActionQueueToExecuteLateUpdateFunc = true;//FIXEDUPDATE IMPL//Holds actions received from another Thread. Will be coped to actionCopiedQueueFixedUpdateFunc then executed from thereprivate static List<System.Action> actionQueuesFixedUpdateFunc = new List<Action>();//holds Actions copied from actionQueuesFixedUpdateFunc to be executedList<System.Action> actionCopiedQueueFixedUpdateFunc = new List<System.Action>();// Used to know if whe have new Action function to execute. This prevents the use of the lock keyword every frameprivate volatile static bool noActionQueueToExecuteFixedUpdateFunc = true;//Used to initialize UnityThread. Call once before any function herepublic static void initUnityThread(bool visible = false){if (instance != null){return;}if (Application.isPlaying){// add an invisible game object to the sceneGameObject 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 IMPLpublic 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 the old actions from the actionCopiedQueueUpdateFunc queueactionCopiedQueueUpdateFunc.Clear();lock (actionQueuesUpdateFunc){//Copy actionQueuesUpdateFunc to the actionCopiedQueueUpdateFunc variableactionCopiedQueueUpdateFunc.AddRange(actionQueuesUpdateFunc);//Now clear the actionQueuesUpdateFunc since we've done copying itactionQueuesUpdateFunc.Clear();noActionQueueToExecuteUpdateFunc = true;}// Loop and execute the functions from the actionCopiedQueueUpdateFuncfor (int i = 0; i < 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 the old actions from the actionCopiedQueueLateUpdateFunc queueactionCopiedQueueLateUpdateFunc.Clear();lock (actionQueuesLateUpdateFunc){//Copy actionQueuesLateUpdateFunc to the actionCopiedQueueLateUpdateFunc variableactionCopiedQueueLateUpdateFunc.AddRange(actionQueuesLateUpdateFunc);//Now clear the actionQueuesLateUpdateFunc since we've done copying itactionQueuesLateUpdateFunc.Clear();noActionQueueToExecuteLateUpdateFunc = true;}// Loop and execute the functions from the actionCopiedQueueLateUpdateFuncfor (int i = 0; i < 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 the old actions from the actionCopiedQueueFixedUpdateFunc queueactionCopiedQueueFixedUpdateFunc.Clear();lock (actionQueuesFixedUpdateFunc){//Copy actionQueuesFixedUpdateFunc to the actionCopiedQueueFixedUpdateFunc variableactionCopiedQueueFixedUpdateFunc.AddRange(actionQueuesFixedUpdateFunc);//Now clear the actionQueuesFixedUpdateFunc since we've done copying itactionQueuesFixedUpdateFunc.Clear();noActionQueueToExecuteFixedUpdateFunc = true;}// Loop and execute the functions from the actionCopiedQueueFixedUpdateFuncfor (int i = 0; i < actionCopiedQueueFixedUpdateFunc.Count; i++){actionCopiedQueueFixedUpdateFunc[i].Invoke();}}
#endifpublic void OnDisable(){if (instance == this){instance = null;}}
}
附上原文链接