[Unity]多线程编程的一点心得
2017-05-03 16:55
288 查看
在做毕设的时候涉及到了较大数据的读取,每次从硬盘读都会卡很久,于是找资料之后自己做了个简单的多线程解决方案。
一共有两个类。第一个类ThreadJob如下:
注意的几点:
通过继承ThreadJob,override ThreadFunction()来实现自己的线程。
主线程直接用构造函数构造一个ThreadJob,然后调用Start()开始运行。自己不断检查isDone来查看线程是否完成。
isDone里使用了.net的原子操作,我不清楚这种写法是否最优。当然也可以直接用lock。
isBackground保证线程会随着主线程的退出而退出。否则主线程退出后该线程不会结束。
WaitTillDone()是一个方便主线程检查isDone的函数。具体使用见后文。
第二个类是ThreadManager,主要用途是子线程向主线程发消息。(比如读取文件的进度等)。因为unity的.net版本没有concurrent容器,这里用的是lock给队列上锁。
要注意的是尽管在instance属性里有FindObjectOfType,但是因为子线程无法使用Unity的函数,所以还是需要在Awake里手动赋值一下。否则如果子线程首先调用了instance属性就会报错。
使用的时候在子线程里调用AddThreadCallback即可。在主线程的下一帧就会调用。
具体使用例子:
用Threadmanager进行通信,Notify函数由子线程调用:
一共有两个类。第一个类ThreadJob如下:
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; using System.Threading; public class ThreadJob { public bool isDone { get { int val = 1; Interlocked.CompareExchange(ref val,0, _isDone); if (val == 0) return true; return false; } set { _isDone = value ? 1 : 0; } } private int _isDone; protected Thread thread; public void Start() { thread = new Thread(Run); thread.IsBackground = true; thread.Start(); } private void Run() { ThreadFunction(); isDone = true; } protected virtual void ThreadFunction() { } public IEnumerator WaitTillDone() { while (!isDone) yield return null; } }
注意的几点:
通过继承ThreadJob,override ThreadFunction()来实现自己的线程。
主线程直接用构造函数构造一个ThreadJob,然后调用Start()开始运行。自己不断检查isDone来查看线程是否完成。
isDone里使用了.net的原子操作,我不清楚这种写法是否最优。当然也可以直接用lock。
isBackground保证线程会随着主线程的退出而退出。否则主线程退出后该线程不会结束。
WaitTillDone()是一个方便主线程检查isDone的函数。具体使用见后文。
第二个类是ThreadManager,主要用途是子线程向主线程发消息。(比如读取文件的进度等)。因为unity的.net版本没有concurrent容器,这里用的是lock给队列上锁。
using System.Collections; using System.Collections.Generic; using UnityEngine; using System; public class ThreadManager : MonoBehaviour { public static ThreadManager instance { get { if (_instance == null) { _instance = FindObjectOfType<ThreadManager>(); } return _instance; } } private static ThreadManager _instance; private void Awake() { _instance = this; //if the first call is used in a thread, it will throw a exception, since sub-thread can't use FindObjectOfType } private Queue<Action> _callbackQueue = new Queue<Action>(); public void AddThreadCallback(Action callback) { lock (_callbackQueue) { _callbackQueue.Enqueue(callback); } } // Update is called once per frame void Update () { lock (_callbackQueue) { while (_callbackQueue.Count > 0) { _callbackQueue.Dequeue()(); } } } }
要注意的是尽管在instance属性里有FindObjectOfType,但是因为子线程无法使用Unity的函数,所以还是需要在Awake里手动赋值一下。否则如果子线程首先调用了instance属性就会报错。
使用的时候在子线程里调用AddThreadCallback即可。在主线程的下一帧就会调用。
具体使用例子:
public void ImportTexture() { var thread = GetReadTextureThread(); thread.Start(); StartCoroutine(ReadMain(thread)); } private IEnumerator ReadMain(ThreadedReadTexture thread) { yield return thread.WaitTillDone(); //注意这里的用法 var info = thread.GetTexture(); _tex = new Texture3D(info.width, info.height, info.thickness, TextureFormat.RFloat, false); _tex.SetPixels(info.data); _tex.Apply(); }
用Threadmanager进行通信,Notify函数由子线程调用:
public void Notify(string progress) { ThreadManager.instance.AddThreadCallback( () => { SystemController.instance.hint.hintText = progress; //显示一条消息 }); }
相关文章推荐
- 多线程编程的一点小心得(1) 推荐
- 关于C#多线程、网络编程与计时器Timer的一点使用心得
- 多线程编程的一点小心得(2)
- 关于exe形式编程的一点心得,希望对大家有所帮助
- 多线程应用程式中调用窗体的一点心得-.NET教程,算法/线程
- 自己对架构网游服务器多线程的一点心得
- 多线程应用程序中调用窗体的一点心得
- 编程一点心得-extern 变量 头文件重复引用
- 关于exe形式编程的一点心得,希望对大家有所帮助
- Java多线程和并发编程实践的学习心得----基础篇3
- JMS(Jboss Messaging)的一点使用心得(十二)多线程的ClassLoader
- 与大家分享一点有关编程的心得
- 编程开发的一点学习心得
- 多线程应用程序中调用窗体的一点心得
- 多线程编程的一点点心得
- Java多线程和并发编程实践的学习心得----基础篇
- 多线程应用程序中调用窗体的一点心得
- 多线程应用程序中调用窗体的一点心得(摘)
- 多线程编程的一点讨论
- [转贴]关于exe形式编程的一点心得,希望对大家有所帮助