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;

    }

}

注意的几点:

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

2.主线程直接用构造函数构造一个ThreadJob,然后调用Start()开始运行。自己不断检查isDone来查看线程是否完成。

3.isDone里使用了.net的原子操作,我不清楚这种写法是否最优。当然也可以直接用lock。

4.isBackground保证线程会随着主线程的退出而退出。否则主线程退出后该线程不会结束。

5.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();

            }

            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 _callbackQueue = new Queue();

 

    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;    //显示一条消息

            });

    }

 

更多unity2018的功能介绍请到paws3d学习中心查找。链接https://www.paws3d.com/learn/,也可以加入unity学习讨论群935714213

近期更有资深开发人士直播分享unity开发经验,详情请进入官网或加入QQ群了解

你可能感兴趣的:(Unity多线程编程的一点心得)