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;}}
}

附上原文链接

UnityThread子线程使用只能在主线程中调用的函数或Unity API相关推荐

  1. [转]Android限制只能在主线程中进行UI访问的实现原理

    目录 Android限制只能在主线程中进行UI访问 Thread的实现 Android Thread 的构造方法 Android Thread 的start()方法 如何在我们自己的代码中去检测当前T ...

  2. Android中Handler消息传递机制应用之子线程不允许操作主线程的组件

    场景 进程 一个Android应用就是一个一个进程,每个应用在各自的进程中运行. 线程 比进程更小的独立运行的基本单位,一个进程可以包含多个线程. 要求 一个TextView和一个Button,点击B ...

  3. java 子线程退出_java – 在子线程完成执行之前主线程将退出吗?

    我读了2篇文章 在上面的文章中,在"线程终止"段中,它在Red中声明"如果父线程终止,它的所有子线程也会终止". 在上面的文章中,该页面的最后一行指出" ...

  4. 多线程遇到的问题:(2)子线程未运行完 主线程结束了

    问题: 用@Test测试多线程接口时,启动服务抛出异常: Singleton bean creation not allowed while singletons of this factory ar ...

  5. 每个java程序都至少有一个线程给主线程,java程序在主线程中判断各个子线程状态的操作,该如何解决...

    java程序在主线程中判断各个子线程状态的操作 每个子线程在队列为空时会wait等待其他线程添加新url到队列,到最后所有子线程都取不到url时也会都wait住,要在主线程中判断如果所有的子线程都是w ...

  6. python主线程执行_在Django vi中的主线程中执行Python函数

    我创建了Django视图"graph",目的是显示从matplotlib.pyplot模块.我编写了我的函数plot\u bubbles(返回amatplotlib.figure. ...

  7. Qt与OpenCV编程:在子线程打开摄像头用主线程显示

    前言 1.在做图像处理开发中,比例做目标跟踪识别的时候,用OpenCV一直在处理摄像头传入的数据,有时候会出现界面卡死或者未响应的状态,这是因为事件循环一直等待处理函数的返回而导致阻塞事件循环,这样一 ...

  8. Unity C# 子线程Action发送到主线程执行

    今天去面试..面试官竟然说子线程的Action不能发送到主线程执行... ...废话不说上干货 using System.Collections; using System.Collections.G ...

  9. android不能在主线程,安卓开发:主线程真的不能做UI操作吗?这一点很多程序员都没想到...

    只要参与过安卓项目开发一两年的朋友们应该清楚,为了避免UI渲染出现异常安卓框架限制UI操作只能在主线程中进行,如果贸然在子线程做了UI操作结果会怎样?我们随便写下了如下测试代码. 不出意外的话,代码执 ...

最新文章

  1. 机器学习(16)ROC曲线与AUC指标(癌症分类的模型检测--AUC指标)
  2. 麦肯锡顾问的整体设计:从大局需要安排工作
  3. Linux下使用dmidecode查看服务器的详细的硬件配置
  4. centos java tomcat_centos配置Tomcat以指定的身份(非root)运行
  5. ant vue 树形菜单横向显示_Vue--组件Ant- 树形结构菜单
  6. ServerBootstrap的启动流程
  7. jzoj2152-终极数【堆】
  8. webkit中对incomplete type指针的处理技巧
  9. Service Mesh(服务网格)
  10. .NET下数据访问层+webform前台 技术大比拼
  11. 唐山职业技术学院计算机专业分数线,唐山职业技术学院历年分数线 2021唐山职业技术学院录取分数线...
  12. mysql 1261 load data_mysql使用load data导入数据文件
  13. 软件测试模型-其他模型(W模型|H模型|X模型)
  14. Halcon图像预处理与形态学(形态学)
  15. 数学实验matlab课后习题,数学实验练习题(MATLAB)
  16. 软考·网络工程师认证(第八章)
  17. 【托业】【新托业TOEIC新题型真题】学习笔记2-题库一--P5-6
  18. “二选一”是支付宝首创,背后是帝国的霸权逻辑
  19. CSS基础-02 background(背景色)(背景色 background-color、背景图 background-image)
  20. IEEE T PAMI投稿注意事项

热门文章

  1. 为什么要将样本方差除以 N-1
  2. SEO组词器:快速寻找合适关键词,优化文章!
  3. 算法系列(十)堆实现优先队列
  4. MySQL的下载、安装配置、连接可视化界面。
  5. Android平台GB28181设备接入端如何支持跨网段语音对讲
  6. 微信订阅号渠道推广带参数二维码如何生成和统计呢?
  7. 车载android系统最新版是多少,通用汽车宣布在2021年全面启用新版Android车载信息娱乐系统...
  8. 参数反演 计算机,叠前各向异性特征参数反演方法及计算机可读存储介质与流程...
  9. redis5.0.5版本搭建集群
  10. 创业文章:长风破浪会有时