unity多线程的学习-Loom-Loom类

/*
Thank you for using "Loom for Unity". This code was written by Michiel Frankfort - Q1 2013.

Features:
- Turn your app into a true Multi-Threaded application overnight! Starting a simple worker/background thread is not a challenge... Utilizing all the available cores for one (or more) heavy-duty tasks is a true challenge! This framework helps you spread the workload to all cores and manage them the easy way.
- Powerfull “DispatchToMainThread” tools, which let you instantiate and directly use Unity-objects from the external threads!
- Three Demo's included:
    Flocking Massive: A Multi-threaded flocking demo, prept to run on a Samsung Galaxy S3 with 7000 boids!!!
    
    Texture blur: Shows how easy it is to use this framework for repetitive tasks, using the “StartMultithreadedWorkloadExecution” tool, which subdivides work into smaller packages and feeds them to multiple cores/threads.
    
    SimpleExampleImplementation: Showing how to use the “Abort”, “DispatchToMainThread-tools” and “WaitForNextFrame” actions.
 
- No Threading experience required: you'll learn fast enough from the provided examples!
- Pick your max Cores/Threads to do the work for you. 
- All ThreadPoolScheduler events (onComplete, onWorkerObjectDone) are fired in the MainThread / GameThread.


Why did I build this?
This framework was initially created as the cornerstone of the Realtime-Raytracing-engine that I'm currently working on (yes, when its done, I'll put it in the store as well)
In order to obtain Realtime-Raytracing, I needed more horsepower and utilize multiple cores while keeping the MainThread alive, smooth & unblocked.
So I ended up building a ThreadScheduler which fires all events in the MainThread, but does not block it.

Any Field-experience so far?
Products always get better when you use them yourself and where born out of need instead of theoretical appliances.
This framework is up and running within my own Raytracer and has proves perfect workload delegation between cores, with low overhead.
For as long as my Raytracer is under development, I'll keep iterating on this tool, and if people actually buy this tool, I'll keep providing Updates :-)

API Documentation: http://www.frankfortsoftware.com/LOOM/Documentation/
Support: [email protected]
 */







using System;
using System.Threading;
using System.Collections.Generic;
using Frankfort.Threading;
using Frankfort.Threading.Internal;
using UnityEngine;





/// 
/// Primairy accespoint/interface to all framework methods & helpers. This is just a static wrapper-class for sake of ease...
/// 
public static class Loom
{




    //--------------------------------------- 2 START SINGLE THREAD OVERLOADS 两个起始线程重载--------------------------------------
    //--------------------------------------- 2 START SINGLE THREAD OVERLOADS --------------------------------------
    #region 2 START SINGLE THREAD OVERLOADS 



    /// 
    /// Starts an method running on a new thread. The Thread dies when the method has stopped running.
    /// 在新线程上运行方法,当方法停止运行时线程死亡
    /// You can now make use of the DispatchToMainThread-actions & WaitForNextFrame
    /// 可以利用DispatchToMainThread-actions 和 WaitForNextFrame
    /// 
    /// The method that will be executed by the new thread
    /// 将被线程执行的目标方法
    /// Thread Priority
    /// 线程优先级
    /// Default TRUE: Executes the targetMethod within a Try-Catch statement and will log any errors back to the MainThread
    /// try-catch安全模式
    /// Newly instantiated Thread
    /// 返回最近的初始化线程
    public static Thread StartSingleThread(ThreadStart targetMethod, System.Threading.ThreadPriority priority = System.Threading.ThreadPriority.Normal, bool safeMode = true)
    {
        return SingleThreadStarter.StartSingleThread(targetMethod, priority, safeMode);
    }




    /// 
    /// Starts an method running on a new thread. The Thread dies when the method has stopped running.
    /// You can now make use of the DispatchToMainThread-actions & WaitForNextFrame
    /// 
    /// The method that will be executed by the new thread
    /// Object to pass to the targetMethod as soon as the Thread is started
    /// 当线程开启时传递给目标方法的参数对象
    /// Thread Priority
    /// Default TRUE: Executes the targetMethod within a Try-Catch statement and will log any errors back to the MainThread
    /// Newly instantiated Thread
    public static Thread StartSingleThread(ParameterizedThreadStart targetMethod, object argument, System.Threading.ThreadPriority priority = System.Threading.ThreadPriority.Normal, bool safeMode = true)
    {
        return SingleThreadStarter.StartSingleThread(targetMethod, argument, priority, safeMode);
    }


    #endregion
    //--------------------------------------- 2 START SINGLE THREAD OVERLOADS --------------------------------------
    //--------------------------------------- 2 START SINGLE THREAD OVERLOADS --------------------------------------













    //--------------------------------------- 4 MULTI THREADED WORK EXECUTION OVERLOADS  4个多线程工作执行重载 --------------------------------------
    //--------------------------------------- 4 MULTI THREADED WORK EXECUTION OVERLOADS --------------------------------------

    #region 4 MULTI THREADED WORK EXECUTION OVERLOADS
    /// 
    /// Helps spreading the same repetetive workload over multiple threads/cores in an easy way.
    /// 分散重复的工作量到多线程去
    /// 
    /// T: Generic-Type of the object you want to be computed by the executor
    /// 泛型对象
    ///  A (static) method that computes one workLoad-object at a time
    /// 每次计算一份工作对象的静态方法
    /// An array with objects you want to get computed by the executor
    /// 对象数组
    /// Fired when all re-packaged workLoad-objects are finished computing
    /// 当全部重打包的工作对象已经完成计算时fired
    /// Fires foreach finished re-packaged set of workLoad-object
    /// 每完成一份工作对象的重打包时fires
    ///  Lets you choose how many threads will be run simultaneously by the threadpool. Default: -1 == number of cores minus one, to make sure the MainThread has at least one core to run on. (quadcore == 1 core Mainthread, 3 cores used by the ThreadPoolScheduler)
    /// 线程池运行的线程数最大量
    /// If Null, a new ThreadPoolScheduler will be instantiated.
    /// 如果为空,将初始化新的线程池调度器
    /// Executes all the computations within try-catch events, logging it the message + stacktrace
    /// 安全模式:try-catch
    /// A ThreadPoolScheduler that handles all the repackaged workLoad-Objects
    /// 返回线程池调度器,它处理所有重打包的工作对象
    public static ThreadPoolScheduler StartMultithreadedWorkloadExecution(ThreadWorkloadExecutor workloadExecutor, T[] workLoad, MultithreadedWorkloadComplete onComplete, MultithreadedWorkloadPackageComplete onPackageComplete, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true)
    {
        return MultithreadedWorkloadHelper.StartMultithreadedWorkloadExecution, T>(workloadExecutor, workLoad, null, onComplete, onPackageComplete, maxThreads, scheduler, safeMode);
    }



    /// 
    /// 索引
    /// Helps spreading the same repetetive workload over multiple threads/cores in an easy way.
    /// Besides the workLoad-object, the current index of the workLoad-array is passed to the Executor-delegate.
    /// 除了工作对象,当前对象数组的索引将被传递给委托执行器
    /// 
    /// T: Generic-Type of the object you want to be computed by the executor
    ///  A (static) method that computes one workLoad-object at a time
    /// An array with objects you want to get computed by the executor
    /// Fired when all re-packaged workLoad-objects are finished computing
    /// Fires foreach finished re-packaged set of workLoad-object
    ///  Lets you choose how many threads will be run simultaneously by the threadpool. Default: -1 == number of cores minus one, to make sure the MainThread has at least one core to run on. (quadcore == 1 core Mainthread, 3 cores used by the ThreadPoolScheduler)
    /// If Null, a new ThreadPoolScheduler will be instantiated.
    /// Executes all the computations within try-catch events, logging it the message + stacktrace
    /// A ThreadPoolScheduler that handles all the repackaged workLoad-Objects
    public static ThreadPoolScheduler StartMultithreadedWorkloadExecution(ThreadWorkloadExecutorIndexed workloadExecutor, T[] workLoad, MultithreadedWorkloadComplete onComplete, MultithreadedWorkloadPackageComplete onPackageComplete, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true)
    {
        return MultithreadedWorkloadHelper.StartMultithreadedWorkloadExecution, T>(workloadExecutor, workLoad, null, onComplete, onPackageComplete, maxThreads, scheduler, safeMode);
    }


    /// 
    /// 参数
    /// Helps spreading the same repetetive workload over multiple threads/cores in an easy way.
    /// Besides the workLoad-object, an extra Argument will be passed to the Executor-delegate
    /// 除了工作对象,还有额外的参数
    /// 
    /// T: Generic-Type of the object you want to be computed by the executor
    ///  A (static) method that computes one workLoad-object at a time
    /// An array with objects you want to get computed by the executor
    /// Fired when all re-packaged workLoad-objects are finished computing
    /// Fires foreach finished re-packaged set of workLoad-object
    ///  Lets you choose how many threads will be run simultaneously by the threadpool. Default: -1 == number of cores minus one, to make sure the MainThread has at least one core to run on. (quadcore == 1 core Mainthread, 3 cores used by the ThreadPoolScheduler)
    /// If Null, a new ThreadPoolScheduler will be instantiated.
    /// Executes all the computations within try-catch events, logging it the message + stacktrace
    /// A ThreadPoolScheduler that handles all the repackaged workLoad-Objects
    public static ThreadPoolScheduler StartMultithreadedWorkloadExecution(ThreadWorkloadExecutorArg workloadExecutor, T[] workLoad, object extraArgument, MultithreadedWorkloadComplete onComplete, MultithreadedWorkloadPackageComplete onPackageComplete, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true)
    {
        return MultithreadedWorkloadHelper.StartMultithreadedWorkloadExecution, T>(workloadExecutor, workLoad, extraArgument, onComplete, onPackageComplete, maxThreads, scheduler, safeMode);
    }


    /// 
    /// 参数+索引
    /// Helps spreading the same repetetive workload over multiple threads/cores in an easy way.
    /// Besides the workLoad-object, an extra Argument & the current index of the workLoad-array is passed to the Executor-delegate.
    /// 
    /// T: Generic-Type of the object you want to be computed by the executor
    ///  A (static) method that computes one workLoad-object at a time
    /// An array with objects you want to get computed by the executor
    /// Fired when all re-packaged workLoad-objects are finished computing
    /// Fires foreach finished re-packaged set of workLoad-object
    ///  Lets you choose how many threads will be run simultaneously by the threadpool. Default: -1 == number of cores minus one, to make sure the MainThread has at least one core to run on. (quadcore == 1 core Mainthread, 3 cores used by the ThreadPoolScheduler)
    /// If Null, a new ThreadPoolScheduler will be instantiated.
    /// Executes all the computations within try-catch events, logging it the message + stacktrace
    /// A ThreadPoolScheduler that handles all the repackaged workLoad-Objects
    public static ThreadPoolScheduler StartMultithreadedWorkloadExecution(ThreadWorkloadExecutorArgIndexed workloadExecutor, T[] workLoad, object extraArgument, MultithreadedWorkloadComplete onComplete, MultithreadedWorkloadPackageComplete onPackageComplete, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true)
    {
        return MultithreadedWorkloadHelper.StartMultithreadedWorkloadExecution, T>(workloadExecutor, workLoad, extraArgument, onComplete, onPackageComplete, maxThreads, scheduler, safeMode);
    }

    #endregion

    //--------------------------------------- 4 MULTI THREADED WORK EXECUTION OVERLOADS --------------------------------------
    //--------------------------------------- 4 MULTI THREADED WORK EXECUTION OVERLOADS --------------------------------------















    //--------------------------------------- THREAD POOL SCHEDULAR  线程池调度器--------------------------------------
    //--------------------------------------- THREAD POOL SCHEDULAR --------------------------------------

    #region THREAD POOL SCHEDULAR


    /// 
    /// Unlike "StartMultithreadedWorkloadExecution", you will have to build your own IThreadWorkerObject.
    /// 自己创建线程工作者对象
    /// Downside: It requires some extra work. Upside: you got more controll over what goes in and comes out
    /// 缺点:需要额外工作  优点:对线程出入有更多控制
    /// Infact: You can create you own polymorphed IThreadWorkerObject-array, each ellement being a completely different type. For example: the statemachines of enemies are IThreadWorkerObject's and the array contains completely different classes with enemies/AI-behaviours.
    /// 可以创建变形的线程工作者对象数组,每个元素可以是完全不同的类型
    /// 
    /// An array of IThreadWorkerObject objects to be handled by the threads. If you want multiple cores/threads to be active, make sure that the number of IThreadWorkerObject's proves matches/exeeds your preferred number maxWorkingThreads. 
    /// 工作者对象数组,若要使用多线程,确保工作对象数量大于指定的最大线程数??
    /// Fired when all re-packaged workLoad-objects are finished computing
    /// Fires foreach finished re-packaged set of workLoad-object
    ///  Lets you choose how many threads will be run simultaneously by the threadpool. Default: -1 == number of cores minus one, to make sure the MainThread has at least one core to run on. (quadcore == 1 core Mainthread, 3 cores used by the ThreadPoolScheduler)
    /// If Null, a new ThreadPoolScheduler will be instantiated.
    /// Executes all the computations within try-catch events, logging it the message + stacktrace
    /// A ThreadPoolScheduler that handles all the repackaged workLoad-Objects
    public static ThreadPoolScheduler StartMultithreadedWorkerObjects(IThreadWorkerObject[] workerObjects, ThreadPoolSchedulerEvent onCompleteCallBack, ThreadedWorkCompleteEvent onPackageExecuted = null, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true)
    {
        if (scheduler == null)
            scheduler = CreateThreadPoolScheduler();

        scheduler.StartASyncThreads(workerObjects, onCompleteCallBack, onPackageExecuted, maxThreads, safeMode);
        return scheduler;
    }



    /// 
    /// Creates an ThreadPoolScheduler instance, which happens to be a Monobehaviour and therefore will showup as gameobject "ThreadPoolScheduler";
    /// 创建线程池调度器实例
    /// 
    /// 
    public static ThreadPoolScheduler CreateThreadPoolScheduler()
    {
        GameObject go = new GameObject("ThreadPoolScheduler");//创建游戏对象
        return go.AddComponent();//挂载组件
    }


    /// 
    /// Creates an ThreadPoolScheduler instance, which happens to be a Monobehaviour and therefore will showup by the name you provide (default: "ThreadPoolScheduler");
    /// 
    /// 
    public static ThreadPoolScheduler CreateThreadPoolScheduler(string name)
    {
        GameObject go = new GameObject(name == null || name == string.Empty ? "ThreadPoolScheduler" : name);//指定名字,更加灵活
        return go.AddComponent();
    }


    #endregion

    //--------------------------------------- THREAD POOL SCHEDULAR --------------------------------------
    //--------------------------------------- THREAD POOL SCHEDULAR --------------------------------------















    //--------------------------------------- THREAD WAIT COMMANDS  线程等待控制--------------------------------------
    //--------------------------------------- THREAD WAIT COMMANDS --------------------------------------

    #region THREAD WAIT COMMANDS

    /// 
    /// Halts/Sleeps the current thread until Unity has rendered a frame. This can be used Coroutine-wise and is safe to be placed within an endless while-loop. Not recommended though...
    /// 停止/休眠当前线程直到Unity提供一帧??,类似协程,适用于while循环
    /// If fired from the MainThread, an error-log will be thrown because its not allowed to freeze the MainThread.
    /// 如果被主线程解除,将会抛出错误提示,因为它不允许freeze主线程
    /// 
    /// By default set to 1. You can let the Thread wait several frames if needed
    /// 单位为帧,默认为1
    public static void WaitForNextFrame(int waitFrames = 1)
    {
        new ThreadWaitForNextFrame(waitFrames);
    }


    /// 
    /// Halts/Sleeps the current thread until "seconds" has expired. This can be used Coroutine-wise and is safe to be placed within an endless while-loop. Not recommended though...
    /// If fired from the MainThread, an error-log will be thrown because its not allowed to freeze the MainThread.
    /// 
    /// Amount of time you want the Thread to sleep.
    /// 单位为秒
    public static void WaitForSeconds(float seconds)
    {
        new ThreadWaitForSeconds(seconds);
    }

    #endregion

    //--------------------------------------- THREAD WAIT COMMANDS --------------------------------------
    //--------------------------------------- THREAD WAIT COMMANDS --------------------------------------














    //--------------------------------------- 4 DISPATCHER OVERLOADS 四个调度员重载--------------------------------------
    //--------------------------------------- 4 DISPATCHER OVERLOADS --------------------------------------

    #region 4 DISPATCHER OVERLOADS



    /// 
    /// Fire and forget一劳永逸: The MainThread will execute this method witout any arguments to pass, nothing will be returned.
    /// 无参无返回
    /// 
    /// Example: "() => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name)" 
    /// 调度器调用,输出信息:被主线程解除的当前线程名
    /// Freezes the thread, waiting for the MainThread to execute & finish the "dispatchCall".
    /// 等待执行:挂起线程,等待主线程执行或被解除
    /// Executes all the computations within try-catch events, logging it the message + stacktrace
    public static void DispatchToMainThread(ThreadDispatchDelegate dispatchCall, bool waitForExecution = false, bool safeMode = true)
    {
        MainThreadDispatcher.DispatchToMainThread(dispatchCall, waitForExecution, safeMode);
    }




    /// 
    /// When executed by the MainThread, this argument will be passed to the "dispatchCall";
    /// 有参无返回
    /// 
    /// Example: "(object obj) => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name + "\nObject: " + obj.toString())"
    /// Once the MainThread executes this action, the argument will be passed to the delegate
    /// Freezes the thread, waiting for the MainThread to execute & finish the "dispatchCall".
    /// Executes all the computations within try-catch events, logging it the message + stacktrace
    public static void DispatchToMainThread(ThreadDispatchDelegateArg dispatchCall, object dispatchArgument, bool waitForExecution = false, bool safeMode = true)
    {
        MainThreadDispatcher.DispatchToMainThread(dispatchCall, dispatchArgument, waitForExecution, safeMode);
    }




    ///      
    /// 有参有返回
    /// When executed by the MainThread, this argument will be passed to the "dispatchCall";
    /// Allows you to dispatch an delegate returning an object (for example: a newly instantiated gameobject) that is directly available in your ThreadPool-Thread.
    /// Because the thread you are dispatching from is not the MainThread, your ThreadPool-thread needs to wait till the MainThread executed the method, and the returned value can be used directly
    /// 
    /// Example: "(object obj) => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name + "\nObject: " + obj.toString())"
    /// Once the MainThread executes this action, the argument will be passed to the delegate
    /// Executes all the computations within try-catch events, logging it the message + stacktrace
    /// After the MainThread has executed the "dispatchCall" (and the worker-thread has been waiting), it will return whatever the dispatchCall returns to the worker-thread
    public static object DispatchToMainThreadReturn(ThreadDispatchDelegateArgReturn dispatchCall, object dispatchArgument, bool safeMode = true)
    {
        return MainThreadDispatcher.DispatchToMainThreadReturn(dispatchCall, dispatchArgument, safeMode);
    }


    /// 
    /// 无参有返回
    /// Allows you to dispatch an delegate returning an object (for example: a newly instantiated gameobject) that is directly available in your ThreadPool-Thread.
    /// Because the thread you are dispatching from is not the MainThread, your ThreadPool-thread needs to wait till the MainThread executed the method, and the returned value can be used directly
    /// 
    /// Example: "(object obj) => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name + "\nObject: " + obj.toString())"
    /// Executes all the computations within try-catch events, logging it the message + stacktrace
    /// After the MainThread has executed the "dispatchCall" (and the worker-thread has been waiting), it will return whatever the dispatchCall returns to the worker-thread
    public static object DispatchToMainThreadReturn(ThreadDispatchDelegateReturn dispatchCall, bool safeMode = true)
    {
        return MainThreadDispatcher.DispatchToMainThreadReturn(dispatchCall, safeMode);
    }


    #endregion

    //--------------------------------------- 4 DISPATCHER OVERLOADS --------------------------------------
    //--------------------------------------- 4 DISPATCHER OVERLOADS --------------------------------------








    //--------------------------------------- CHECK UNITY ACTIVITY  核查Unity活动状态--------------------------------------
    //--------------------------------------- CHECK UNITY ACTIVITY --------------------------------------
    #region CHECK UNITY ACTIVITY

    /// 
    /// A easy way to check if Unity is still running, focused and not pauzed.
    /// 检查unity是否在运行
    /// This comes in handy if threads keep running heavy workloads on seperate threads while IOS for example tries to puch the Application to the background.
    /// 应用在:当线程持续执行繁重工作量时
    /// If you are executing a giant routine on a seperate thread that takes several seconds per cycle, you might want to check regularly if unity is still active by using this check.
    /// 能定期检查unity是否在运行
    /// 
    /// Returns TRUE if Unity is still running, not pauzed and has focus. 
    /// 返回布尔值
    public static bool CheckUnityActive()
    {
        return UnityActivityWatchdog.CheckUnityActive();
    }




    /// 
    /// !IMPORTANT! This method should be called regularly within routines that take more then half a second to complete, to make sure IOS for example is able to force an application to sleep when it looses focus or gets puched to the background.
    /// 这个方法将被定期调用
    /// This is a very light-weight check, internally it only needs to check two static booleans once everything is Initialized and running.
    /// 轻量级程序,本质上当程序已经初始化并且在运行时只要检查两个静态布尔值
    /// You can use this without causing any serious overhead.
    /// 消耗不大
    /// Motivation: Sins Threads cannot be put asleep from the outside, it needs the be managed from within the thread itself, thats why this method was build.
    /// 出问题线程不能从外界被唤醒,只能从线程本身进行管理
    /// Example:
    /// for(int i = 0; i < 999999999; i++)
    /// {
    ///     Loom.SleepOrAbortIfUnityInactive(); //Prevents IOS for example of killing this app because the threads won't sleep once your unity-app is puched to the background.
    ///     //Do something heavy that will cause this routine to run more then 0.5 seconds.
    /// }
    /// 
    public static void SleepOrAbortIfUnityInactive()
    {
        UnityActivityWatchdog.SleepOrAbortIfUnityInactive();
    }
    #endregion
    //--------------------------------------- CHECK UNITY ACTIVITY --------------------------------------
    //--------------------------------------- CHECK UNITY ACTIVITY --------------------------------------










    //--------------------------------------- MAIN THREAD WATCHDOG  主线程监测器--------------------------------------
    //--------------------------------------- MAIN THREAD WATCHDOG --------------------------------------
    #region MAIN THREAD WATCHDOG

    /// 
    /// If you need your current code to be running on the MainThread, you can always call this method to check if its the MainThread or not...
    /// 如果当前代码需要被主线程执行,你可以调用这个方法检查它是否是主线程
    /// 
    /// Returns TRUE if its the MainThread
    /// 若是主线程返回true
    public static bool CheckIfMainThread()
    {
        return MainThreadWatchdog.CheckIfMainThread();
    }


    #endregion
    //--------------------------------------- MAIN THREAD WATCHDOG --------------------------------------
    //--------------------------------------- MAIN THREAD WATCHDOG --------------------------------------

}

你可能感兴趣的:(c#,多线程,unity)