在做毕设的时候涉及到了较大数据的读取,每次从硬盘读都会卡很久,于是找资料之后自己做了个简单的多线程解决方案。

一共有两个类。第一个类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;
}
}

注意的几点:

0. 通过继承ThreadJob,override ThreadFunction()来实现自己的线程。

  1. 主线程直接用构造函数构造一个ThreadJob,然后调用Start()开始运行。自己不断检查isDone来查看线程是否完成。
  2. isDone里使用了.net的原子操作,我不清楚这种写法是否最优。当然也可以直接用lock。
  3. isBackground保证线程会随着主线程的退出而退出。否则主线程退出后该线程不会结束。
  4. 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. Qt:QObject translate
  2. MongoDB的C#官方驱动InvalidOperationException异常的解决办法
  3. NSString NSUrl 相互转化
  4. win8.1 user profile service 服务登录失败
  5. document.elementFromPoint在IE8下无法稳定获取当前坐标元素的解决方法
  6. bitnami-redmine 安装与插件使用
  7. js瀑布流
  8. English Training Material - 02
  9. 为php安装memcached扩展连接memcached服务器
  10. commons-lang3-3.4.jar
  11. Introduction to SharePoint hierarchy
  12. 使用 gulp-file-include 构建前端静态页面
  13. 如何巧妙的利用selenium和requests组合来进行操作需要登录的页面
  14. ACE工具概述
  15. 详解Python的装饰器
  16. Java_04循环结构
  17. python------Socket网略编程
  18. HBase脚本命令
  19. spring 的 切片Aspect 最常用记录方法执行时间
  20. BZOJ3578:GTY的人类基因组计划2(集合hash,STL)

热门文章

  1. 在 Range 对象中,Min (14)必须小于或等于 max (-1)。
  2. HDU 2148 Score
  3. ZOJ 1913 J-Eucild&#39;s Game
  4. Jenkins系列-Jenkins升级、迁移和备份
  5. IIS安装出现“安装程序无法复制文件CONVLOG.EX_”的解决办法
  6. JSTL标签之核心标签
  7. Qt Pro文件与Qt模块启用
  8. bzoj2257[POI2011]Programming Contest
  9. Java入门之:基本数据类型
  10. Windows7上安装Git