zoukankan      html  css  js  c++  java
  • [Unity]多线程编程的一点心得

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

    一共有两个类。第一个类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;    //显示一条消息
                });
        }
    
  • 相关阅读:
    svn checkout单个文件
    ubuntu下使用fstab挂载硬盘时,属于root,如何把它改为属于一个用户的(如sgjm)
    TCP/IP 端口号大全
    Netstat命令详解(windows下)
    Linux netstat命令详解
    windows下用cmd命令netstat查看系统端口使用情况
    LR函数基础(一)(二)
    loadrunner error 27796 Failed to connect to server
    安装lr时无法将值Disable Script Debugger 写入注册表
    LR接口性能测试提示Code
  • 原文地址:https://www.cnblogs.com/yangrouchuan/p/6802769.html
Copyright © 2011-2022 走看看