unity多线程的学习-Loom-Loom类
来源:互联网 发布:域名代理商 编辑:程序博客网 时间:2024/05/29 04:48
using System;
using System.Threading;
using System.Collections.Generic;
using Frankfort.Threading;
using Frankfort.Threading.Internal;
using UnityEngine;
/// <summary>
/// Primairy accespoint/interface to all framework methods & helpers. This is just a static wrapper-class for sake of ease...
/// </summary>
public static class Loom
{
//--------------------------------------- 2 START SINGLE THREAD OVERLOADS 两个起始线程重载--------------------------------------
//--------------------------------------- 2 START SINGLE THREAD OVERLOADS --------------------------------------
#region 2 START SINGLE THREAD OVERLOADS
/// <summary>
/// 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
/// </summary>
/// <param name="targetMethod">The method that will be executed by the new thread</param>
/// 将被线程执行的目标方法
/// <param name="priority">Thread Priority</param>
/// 线程优先级
/// <param name="safeMode">Default TRUE: Executes the targetMethod within a Try-Catch statement and will log any errors back to the MainThread</param>
/// try-catch安全模式
/// <returns>Newly instantiated Thread</returns>
/// 返回最近的初始化线程
public static Thread StartSingleThread(ThreadStart targetMethod, System.Threading.ThreadPriority priority = System.Threading.ThreadPriority.Normal, bool safeMode = true)
{
return SingleThreadStarter.StartSingleThread(targetMethod, priority, safeMode);
}
/// <summary>
/// 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
/// </summary>
/// <param name="targetMethod">The method that will be executed by the new thread</param>
/// <param name="argument">Object to pass to the targetMethod as soon as the Thread is started</param>
/// 当线程开启时传递给目标方法的参数对象
/// <param name="priority">Thread Priority</param>
/// <param name="safeMode">Default TRUE: Executes the targetMethod within a Try-Catch statement and will log any errors back to the MainThread</param>
/// <returns>Newly instantiated Thread</returns>
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
/// <summary>
/// Helps spreading the same repetetive workload over multiple threads/cores in an easy way.
/// 分散重复的工作量到多线程去
/// </summary>
/// <typeparam name="T">T: Generic-Type of the object you want to be computed by the executor</typeparam>
/// 泛型对象
/// <param name="staticWorkloadExecutor"> A (static) method that computes one workLoad-object at a time</param>
/// 每次计算一份工作对象的静态方法
/// <param name="workLoad">An array with objects you want to get computed by the executor</param>
/// 对象数组
/// <param name="onComplete">Fired when all re-packaged workLoad-objects are finished computing</param>
/// 当全部重打包的工作对象已经完成计算时fired
/// <param name="onPackageExecuted">Fires foreach finished re-packaged set of workLoad-object</param>
/// 每完成一份工作对象的重打包时fires
/// <param name="maxThreads"> 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)</param>
/// 线程池运行的线程数最大量
/// <param name="scheduler">If Null, a new ThreadPoolScheduler will be instantiated.</param>
/// 如果为空,将初始化新的线程池调度器
/// <param name="safeMode">Executes all the computations within try-catch events, logging it the message + stacktrace</param>
/// 安全模式:try-catch
/// <returns>A ThreadPoolScheduler that handles all the repackaged workLoad-Objects</returns>
/// 返回线程池调度器,它处理所有重打包的工作对象
public static ThreadPoolScheduler StartMultithreadedWorkloadExecution<T>(ThreadWorkloadExecutor<T> workloadExecutor, T[] workLoad, MultithreadedWorkloadComplete<T> onComplete, MultithreadedWorkloadPackageComplete<T> onPackageComplete, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true)
{
return MultithreadedWorkloadHelper.StartMultithreadedWorkloadExecution<ThreadWorkloadExecutor<T>, T>(workloadExecutor, workLoad, null, onComplete, onPackageComplete, maxThreads, scheduler, safeMode);
}
/// <summary>
/// 索引
/// 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.
/// 除了工作对象,当前对象数组的索引将被传递给委托执行器
/// </summary>
/// <typeparam name="T">T: Generic-Type of the object you want to be computed by the executor</typeparam>
/// <param name="staticWorkloadExecutor"> A (static) method that computes one workLoad-object at a time</param>
/// <param name="workLoad">An array with objects you want to get computed by the executor</param>
/// <param name="onComplete">Fired when all re-packaged workLoad-objects are finished computing</param>
/// <param name="onPackageExecuted">Fires foreach finished re-packaged set of workLoad-object</param>
/// <param name="maxThreads"> 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)</param>
/// <param name="scheduler">If Null, a new ThreadPoolScheduler will be instantiated.</param>
/// <param name="safeMode">Executes all the computations within try-catch events, logging it the message + stacktrace</param>
/// <returns>A ThreadPoolScheduler that handles all the repackaged workLoad-Objects</returns>
public static ThreadPoolScheduler StartMultithreadedWorkloadExecution<T>(ThreadWorkloadExecutorIndexed<T> workloadExecutor, T[] workLoad, MultithreadedWorkloadComplete<T> onComplete, MultithreadedWorkloadPackageComplete<T> onPackageComplete, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true)
{
return MultithreadedWorkloadHelper.StartMultithreadedWorkloadExecution<ThreadWorkloadExecutorIndexed<T>, T>(workloadExecutor, workLoad, null, onComplete, onPackageComplete, maxThreads, scheduler, safeMode);
}
/// <summary>
/// 参数
/// 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
/// 除了工作对象,还有额外的参数
/// </summary>
/// <typeparam name="T">T: Generic-Type of the object you want to be computed by the executor</typeparam>
/// <param name="staticWorkloadExecutor"> A (static) method that computes one workLoad-object at a time</param>
/// <param name="workLoad">An array with objects you want to get computed by the executor</param>
/// <param name="onComplete">Fired when all re-packaged workLoad-objects are finished computing</param>
/// <param name="onPackageExecuted">Fires foreach finished re-packaged set of workLoad-object</param>
/// <param name="maxThreads"> 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)</param>
/// <param name="scheduler">If Null, a new ThreadPoolScheduler will be instantiated.</param>
/// <param name="safeMode">Executes all the computations within try-catch events, logging it the message + stacktrace</param>
/// <returns>A ThreadPoolScheduler that handles all the repackaged workLoad-Objects</returns>
public static ThreadPoolScheduler StartMultithreadedWorkloadExecution<T>(ThreadWorkloadExecutorArg<T> workloadExecutor, T[] workLoad, object extraArgument, MultithreadedWorkloadComplete<T> onComplete, MultithreadedWorkloadPackageComplete<T> onPackageComplete, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true)
{
return MultithreadedWorkloadHelper.StartMultithreadedWorkloadExecution<ThreadWorkloadExecutorArg<T>, T>(workloadExecutor, workLoad, extraArgument, onComplete, onPackageComplete, maxThreads, scheduler, safeMode);
}
/// <summary>
/// 参数+索引
/// 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.
/// </summary>
/// <typeparam name="T">T: Generic-Type of the object you want to be computed by the executor</typeparam>
/// <param name="staticWorkloadExecutor"> A (static) method that computes one workLoad-object at a time</param>
/// <param name="workLoad">An array with objects you want to get computed by the executor</param>
/// <param name="onComplete">Fired when all re-packaged workLoad-objects are finished computing</param>
/// <param name="onPackageExecuted">Fires foreach finished re-packaged set of workLoad-object</param>
/// <param name="maxThreads"> 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)</param>
/// <param name="scheduler">If Null, a new ThreadPoolScheduler will be instantiated.</param>
/// <param name="safeMode">Executes all the computations within try-catch events, logging it the message + stacktrace</param>
/// <returns>A ThreadPoolScheduler that handles all the repackaged workLoad-Objects</returns>
public static ThreadPoolScheduler StartMultithreadedWorkloadExecution<T>(ThreadWorkloadExecutorArgIndexed<T> workloadExecutor, T[] workLoad, object extraArgument, MultithreadedWorkloadComplete<T> onComplete, MultithreadedWorkloadPackageComplete<T> onPackageComplete, int maxThreads = -1, ThreadPoolScheduler scheduler = null, bool safeMode = true)
{
return MultithreadedWorkloadHelper.StartMultithreadedWorkloadExecution<ThreadWorkloadExecutorArgIndexed<T>, 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
/// <summary>
/// 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.
/// 可以创建变形的线程工作者对象数组,每个元素可以是完全不同的类型
/// </summary>
/// <param name="workerObjects">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. </param>
/// 工作者对象数组,若要使用多线程,确保工作对象数量大于指定的最大线程数??
/// <param name="onComplete">Fired when all re-packaged workLoad-objects are finished computing</param>
/// <param name="onPackageExecuted">Fires foreach finished re-packaged set of workLoad-object</param>
/// <param name="maxThreads"> 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)</param>
/// <param name="scheduler">If Null, a new ThreadPoolScheduler will be instantiated.</param>
/// <param name="safeMode">Executes all the computations within try-catch events, logging it the message + stacktrace</param>
/// <returns>A ThreadPoolScheduler that handles all the repackaged workLoad-Objects</returns>
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;
}
/// <summary>
/// Creates an ThreadPoolScheduler instance, which happens to be a Monobehaviour and therefore will showup as gameobject "ThreadPoolScheduler";
/// 创建线程池调度器实例
/// </summary>
/// <returns></returns>
public static ThreadPoolScheduler CreateThreadPoolScheduler()
{
GameObject go = new GameObject("ThreadPoolScheduler");//创建游戏对象
return go.AddComponent<ThreadPoolScheduler>();//挂载组件
}
/// <summary>
/// Creates an ThreadPoolScheduler instance, which happens to be a Monobehaviour and therefore will showup by the name you provide (default: "ThreadPoolScheduler");
/// </summary>
/// <returns></returns>
public static ThreadPoolScheduler CreateThreadPoolScheduler(string name)
{
GameObject go = new GameObject(name == null || name == string.Empty ? "ThreadPoolScheduler" : name);//指定名字,更加灵活
return go.AddComponent<ThreadPoolScheduler>();
}
#endregion
//--------------------------------------- THREAD POOL SCHEDULAR --------------------------------------
//--------------------------------------- THREAD POOL SCHEDULAR --------------------------------------
//--------------------------------------- THREAD WAIT COMMANDS 线程等待控制--------------------------------------
//--------------------------------------- THREAD WAIT COMMANDS --------------------------------------
#region THREAD WAIT COMMANDS
/// <summary>
/// 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主线程
/// </summary>
/// <param name="waitFrames">By default set to 1. You can let the Thread wait several frames if needed</param>
/// 单位为帧,默认为1
public static void WaitForNextFrame(int waitFrames = 1)
{
new ThreadWaitForNextFrame(waitFrames);
}
/// <summary>
/// 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.
/// </summary>
/// <param name="seconds">Amount of time you want the Thread to sleep.</param>
/// 单位为秒
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
/// <summary>
/// Fire and forget: The MainThread will execute this method witout any arguments to pass, nothing will be returned.
/// 无参无返回
/// </summary>
/// <param name="dispatchCall">Example: "() => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name)" </param>
/// 调度器调用,输出信息:被主线程解除的当前线程名
/// <param name="waitForExecution">Freezes the thread, waiting for the MainThread to execute & finish the "dispatchCall".</param>
/// 等待执行:挂起线程,等待主线程执行或被解除
/// <param name="safeMode">Executes all the computations within try-catch events, logging it the message + stacktrace</param>
public static void DispatchToMainThread(ThreadDispatchDelegate dispatchCall, bool waitForExecution = false, bool safeMode = true)
{
MainThreadDispatcher.DispatchToMainThread(dispatchCall, waitForExecution, safeMode);
}
/// <summary>
/// When executed by the MainThread, this argument will be passed to the "dispatchCall";
/// 有参无返回
/// </summary>
/// <param name="dispatchCall">Example: "(object obj) => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name + "\nObject: " + obj.toString())"</param>
/// <param name="dispatchArgument">Once the MainThread executes this action, the argument will be passed to the delegate</param>
/// <param name="waitForExecution">Freezes the thread, waiting for the MainThread to execute & finish the "dispatchCall".</param>
/// <param name="safeMode">Executes all the computations within try-catch events, logging it the message + stacktrace</param>
public static void DispatchToMainThread(ThreadDispatchDelegateArg dispatchCall, object dispatchArgument, bool waitForExecution = false, bool safeMode = true)
{
MainThreadDispatcher.DispatchToMainThread(dispatchCall, dispatchArgument, waitForExecution, safeMode);
}
/// <summary>
/// 有参有返回
/// 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
/// </summary>
/// <param name="dispatchCall">Example: "(object obj) => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name + "\nObject: " + obj.toString())"</param>
/// <param name="dispatchArgument">Once the MainThread executes this action, the argument will be passed to the delegate</param>
/// <param name="safeMode">Executes all the computations within try-catch events, logging it the message + stacktrace</param>
/// <returns>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</returns>
public static object DispatchToMainThreadReturn(ThreadDispatchDelegateArgReturn dispatchCall, object dispatchArgument, bool safeMode = true)
{
return MainThreadDispatcher.DispatchToMainThreadReturn(dispatchCall, dispatchArgument, safeMode);
}
/// <summary>
/// 无参有返回
/// 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
/// </summary>
/// <param name="dispatchCall">Example: "(object obj) => Debug.Log("This will be fired from the MainThread: " + System.Threading.Thread.CurrentThread.Name + "\nObject: " + obj.toString())"</param>
/// <param name="safeMode">Executes all the computations within try-catch events, logging it the message + stacktrace</param>
/// <returns>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</returns>
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
/// <summary>
/// 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是否在运行
/// </summary>
/// <returns>Returns TRUE if Unity is still running, not pauzed and has focus. </returns>
/// 返回布尔值
public static bool CheckUnityActive()
{
return UnityActivityWatchdog.CheckUnityActive();
}
/// <summary>
/// !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.
/// }
/// </summary>
public static void SleepOrAbortIfUnityInactive()
{
UnityActivityWatchdog.SleepOrAbortIfUnityInactive();
}
#endregion
//--------------------------------------- CHECK UNITY ACTIVITY --------------------------------------
//--------------------------------------- CHECK UNITY ACTIVITY --------------------------------------
//--------------------------------------- MAIN THREAD WATCHDOG 主线程监测器--------------------------------------
//--------------------------------------- MAIN THREAD WATCHDOG --------------------------------------
#region MAIN THREAD WATCHDOG
/// <summary>
/// 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...
/// 如果当前代码需要被主线程执行,你可以调用这个方法检查它是否是主线程
/// </summary>
/// <returns>Returns TRUE if its the MainThread</returns>
/// 若是主线程返回true
public static bool CheckIfMainThread()
{
return MainThreadWatchdog.CheckIfMainThread();
}
#endregion
//--------------------------------------- MAIN THREAD WATCHDOG --------------------------------------
//--------------------------------------- MAIN THREAD WATCHDOG --------------------------------------
}
0 0
- unity多线程的学习-Loom-Loom类
- unity多线程的学习:Loom-IThreadWorkerObject部分
- (小白)unity多线程的学习:Loom-ThreadPoolScheduler类
- Unity-Loom的多线程研究及优化
- Unity中使用Loom工具,Unity多线程学习
- unity 线程库 Loom 的初步使用
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Unity多线程(Thread)和主线程(MainThread)交互使用类——Loom工具分享
- Loom工具
- 实验楼Linux学习笔记(八)之任务计划crontab
- 程序员如何做到『编程速度又快,Bug 数量又少』?
- C++ 默认构造函数
- javap使用实例图解
- ARM学习视频观後感:ARM那些你得知道的事儿 1-5
- unity多线程的学习-Loom-Loom类
- Spring Boot 集成 log4j2
- Linux下 unrar unzip 解压
- git 版本控制冲突解决
- 李笑来《把时间当做朋友》——兴趣真的那么重要么?
- java对象序列化示例
- 仿QQ相册RecyclerView滑动选中
- maven教程(三):maven项目创建
- ubuntu交叉编译环境搭建