zoukankan      html  css  js  c++  java
  • 结合Thread Ninja明确与处理异步协程中的异常

    Thread Ninja说明:

    Thread Ninja - Multithread Coroutine

    Requires Unity 3.4.0 or higher.

    A simple script helps you write multithread coroutines. 

    Unity's coroutine is great, but it's not a real thread. And a background thread is not allowed to access Unity's API. 

    Thread Ninja combines coroutine & background thread, make a method both a coroutine and a background thread, makes your life easy with multithread programming.
     
    对于yield语句不涉在try...catch中的情况:
     1     // Use this for initialization
     2     void Start ()
     3     {
     4         GotoState(RunningBaseState.time);
     5         this.StartCoroutineAsync(AsyncCoroutine());
     6     }
     7 
     8     IEnumerator AsyncCoroutine()
     9     {
    10         while (true)
    11         {
    12             try
    13             {
    14                 File.OpenRead("NotExist");
    15             }
    16             catch (Exception e)
    17             {
    18                 ZSLoger.Instance.Loger.Debug(e.Message);
    19             }
    20             Thread.Sleep(1000);
    21             yield return ZS.JumpToUnity;
    22             ZSLoger.Instance.Loger.Debug("Jump 2 unity in AsyncCoroutine.");
    23             yield return ZS.JumpBack;
    24         }
    25     }

    输出结果:

     
     
    因为yield语句不能在try...catch中的情况修改Task.cs:
      1 using UnityEngine;
      2 using System.Collections;
      3 using System.Threading;
      4 
      5 namespace ZSThread
      6 {
      7     /// <summary>
      8     /// Represents an async task.
      9     /// </summary>
     10     public class Task : IEnumerator
     11     {        
     12         // implements IEnumerator to make it usable by StartCoroutine;
     13         #region IEnumerator Interface
     14         /// <summary>
     15         /// The current iterator yield return value.
     16         /// </summary>
     17         public object Current { get; private set; }
     18 
     19         /// <summary>
     20         /// Runs next iteration.
     21         /// </summary>
     22         /// <returns><code>true</code> for continue, otherwise <code>false</code>.</returns>
     23         public bool MoveNext()
     24         {
     25             return OnMoveNext();
     26         }
     27 
     28         public void Reset()
     29         {
     30             // Reset method not supported by iterator;
     31             throw new System.NotSupportedException(
     32                 "Not support calling Reset() on iterator.");
     33         }
     34         #endregion
     35 
     36         // inner running state used by state machine;
     37         public enum RunningState
     38         {
     39             Init,
     40             RunningAsync,
     41             PendingYield,
     42             ToBackground,
     43             RunningSync,
     44             CancellationRequested,
     45             Done,
     46             Error
     47         }
     48 
     49         // routine user want to run;
     50         protected readonly IEnumerator _innerRoutine;
     51 
     52         // current running state;
     53         private RunningState _state;
     54         // last running state;
     55         private RunningState _previousState;
     56         // temporary stores current yield return value
     57         // until we think Unity coroutine engine is OK to get it;
     58         private object _pendingCurrent;
     59 
     60         /// <summary>
     61         /// Gets state of the task.
     62         /// </summary>
     63         public TaskState State
     64         {
     65             get
     66             {
     67                 switch (_state)
     68                 {
     69                     case RunningState.CancellationRequested:
     70                         return TaskState.Cancelled;
     71                     case RunningState.Done:
     72                         return TaskState.Done;
     73                     case RunningState.Error:
     74                         return TaskState.Error;
     75                     case RunningState.Init:
     76                         return TaskState.Init;
     77                     default:
     78                         return TaskState.Running;
     79                 }
     80             }
     81         }
     82 
     83         /// <summary>
     84         /// Gets exception during running.
     85         /// </summary>
     86         public System.Exception Exception { get; protected set; }
     87 
     88         public Task(IEnumerator routine)
     89         {
     90             _innerRoutine = routine;
     91             // runs into background first;
     92             _state = RunningState.Init;
     93         }
     94 
     95         /// <summary>
     96         /// Cancel the task till next iteration;
     97         /// </summary>
     98         public void Cancel()
     99         {
    100             if (State == TaskState.Running)
    101             {
    102                 GotoState(RunningState.CancellationRequested);
    103             }
    104         }
    105 
    106         /// <summary>
    107         /// A co-routine that waits the task.
    108         /// </summary>
    109         public IEnumerator Wait()
    110         {
    111             while (State == TaskState.Running)
    112                 yield return null;
    113         }
    114 
    115         // thread safely switch running state;
    116         protected void GotoState(RunningState state)
    117         {
    118             if (_state == state) return;
    119 
    120             lock (this)
    121             {
    122                 // maintainance the previous state;
    123                 _previousState = _state;
    124                 _state = state;
    125             }
    126         }
    127 
    128         // thread safely save yield returned value;
    129         protected void SetPendingCurrentObject(object current)
    130         {
    131             lock (this)
    132             {
    133                 _pendingCurrent = current;
    134             }
    135         }
    136 
    137         // actual MoveNext method, controls running state;
    138         protected bool OnMoveNext()
    139         {
    140             // no running for null;
    141             if (_innerRoutine == null)
    142                 return false;
    143 
    144             // set current to null so that Unity not get same yield value twice;
    145             Current = null;
    146 
    147             // loops until the inner routine yield something to Unity;
    148             while (true)
    149             {
    150                 // a simple state machine;
    151                 switch (_state)
    152                 {
    153                     // first, goto background;
    154                     case RunningState.Init:
    155                         GotoState(RunningState.ToBackground);
    156                         break;
    157                     // running in background, wait a frame;
    158                     case RunningState.RunningAsync:
    159                         return true;
    160 
    161                     // runs on main thread;
    162                     case RunningState.RunningSync:
    163                         MoveNextUnity();
    164                         break;
    165 
    166                     // need switch to background;
    167                     case RunningState.ToBackground:
    168                         GotoState(RunningState.RunningAsync);
    169                         // call the thread launcher;
    170                         MoveNextAsync();
    171                         return true;
    172 
    173                     // something was yield returned;
    174                     case RunningState.PendingYield:
    175                         if (_pendingCurrent == ZS.JumpBack)
    176                         {
    177                             // do not break the loop, switch to background;
    178                             GotoState(RunningState.ToBackground);
    179                         }
    180                         else if (_pendingCurrent == ZS.JumpToUnity)
    181                         {
    182                             // do not break the loop, switch to main thread;
    183                             GotoState(RunningState.RunningSync);
    184                         }
    185                         else
    186                         {
    187                             // not from the ZS, then Unity should get noticed,
    188                             // Set to Current property to achieve this;
    189                             Current = _pendingCurrent;
    190 
    191                             // yield from background thread, or main thread?
    192                             if (_previousState == RunningState.RunningAsync)
    193                             {
    194                                 // if from background thread, 
    195                                 // go back into background in the next loop;
    196                                 _pendingCurrent = ZS.JumpBack;
    197                             }
    198                             else
    199                             {
    200                                 // otherwise go back to main thread the next loop;
    201                                 _pendingCurrent = ZS.JumpToUnity;
    202                             }
    203 
    204                             // end this iteration and Unity get noticed;
    205                             return true;
    206                         }
    207                         break;
    208 
    209                     // done running, pass false to Unity;
    210                     case RunningState.Done:
    211                     case RunningState.CancellationRequested:
    212                     default:
    213                         return false;
    214                 }
    215             }
    216         }
    217 
    218         // background thread launcher;
    219         protected void MoveNextAsync()
    220         {
    221             ThreadPool.QueueUserWorkItem(
    222                 new WaitCallback(BackgroundRunner));
    223         }
    224 
    225         // background thread function;
    226         protected void BackgroundRunner(object state)
    227         {
    228             // just run the sync version on background thread;
    229             MoveNextUnity();
    230         }
    231 
    232         // run next iteration on main thread;
    233         protected virtual void MoveNextUnity()
    234         {
    235             try
    236             {
    237                 // run next part of the user routine;
    238                 var result = _innerRoutine.MoveNext();
    239 
    240                 if (result)
    241                 {
    242                     // something has been yield returned, handle it;
    243                     SetPendingCurrentObject(_innerRoutine.Current);
    244                     GotoState(RunningState.PendingYield);
    245                 }
    246                 else
    247                 {
    248                     // user routine simple done;
    249                     GotoState(RunningState.Done);
    250                 }
    251             }
    252             catch (System.Exception ex)
    253             {
    254                 // exception handling, save & log it;
    255                 this.Exception = ex;
    256                 Debug.LogError(string.Format("{0}
    {1}", ex.Message, ex.StackTrace));
    257                 // then terminates the task;
    258                 GotoState(RunningState.Error);
    259             }
    260         }
    261     }
    262 }
    View Code

    使用情况:

      1 using System.Collections;
      2 using System.Collections.Generic;
      3 using System.IO;
      4 using System.Threading;
      5 using UnityEngine;
      6 using UnityEngine.Events;
      7 using ZSThread;
      8 
      9 public class RunLogicManager : SingletonLimit<RunLogicManager>
     10 {
     11     private RunningBaseState mState;
     12     private Stack<RunningBaseState> mStateStack = new Stack<RunningBaseState>();
     13 
     14     public static RunLogicManager Instance
     15     {
     16         get
     17         {
     18             return (RunLogicManager)mInstance;
     19         }
     20         set
     21         {
     22             mInstance = value;
     23         }
     24     }
     25 
     26     private void GotoState(RunningBaseState state)
     27     {
     28         if (mStateStack.Count > 0)
     29         {
     30             var tempState = mStateStack.Pop();
     31             tempState.Exit();
     32         }
     33         mState = state;
     34         mStateStack.Push(mState);
     35         mState.Enter();
     36     }
     37 
     38     // Use this for initialization
     39     void Start ()
     40     {
     41         GotoState(RunningBaseState.time);
     42 
     43         ExceptionTask t = new ExceptionTask(AsyncCoroutine(), mono =>
     44         {
     45             ZSLoger.Instance.Loger.Debug("处理异常,此调用处于多线程.");
     46         }, this);
     47         StartCoroutine(t);
     48     }
     49 
     50     IEnumerator AsyncCoroutine()
     51     {
     52         while (true)
     53         {
     54             File.OpenRead("NotExist");
     55             Thread.Sleep(1000);
     56             yield return ZS.JumpToUnity;
     57             ZSLoger.Instance.Loger.Debug("Jump 2 unity in AsyncCoroutine.");
     58             yield return ZS.JumpBack;
     59         }
     60     }
     61 
     62     // Update is called once per frame
     63     void Update ()
     64     {
     65         
     66     }
     67 }
     68 
     69 public class ExceptionTask : Task
     70 {
     71     private MonoBehaviour mono;
     72     private UnityAction<MonoBehaviour> exceptionHandle;
     73     public ExceptionTask(IEnumerator routine, UnityAction<MonoBehaviour> exceptionHandle, MonoBehaviour mono) : base(routine)
     74     {
     75         this.mono = mono;
     76         this.exceptionHandle = exceptionHandle;
     77     }
     78 
     79     // run next iteration on main thread;
     80     protected override void MoveNextUnity()
     81     {
     82         try
     83         {
     84             // run next part of the user routine;
     85             var result = _innerRoutine.MoveNext();
     86 
     87             if (result)
     88             {
     89                 // something has been yield returned, handle it;
     90                 SetPendingCurrentObject(_innerRoutine.Current);
     91                 GotoState(RunningState.PendingYield);
     92             }
     93             else
     94             {
     95                 // user routine simple done;
     96                 GotoState(RunningState.Done);
     97             }
     98         }
     99         catch (System.Exception ex)
    100         {
    101             this.Exception = ex;
    102             //Debug.LogError(string.Format("{0}
    {1}", ex.Message, ex.StackTrace));
    103             ZSLoger.Instance.Loger.Debug("handle exception.");
    104             if (exceptionHandle != null)
    105             {
    106                 exceptionHandle.Invoke(mono);
    107             }
    108             // then terminates the task;
    109             GotoState(RunningState.Error);
    110         }
    111     }
    112 }
    View Code

    输出结果:

    关于unity协程深度的扩展参考博文:http://blog.csdn.net/ybhjx/article/details/55188777

  • 相关阅读:
    saltstack源码详解一
    linux的yum报错
    django restframework
    列表生成式
    面向对象的封装
    linux对于zombie的处理
    Flask学习目录
    #1_两数之和
    LeetCode入门
    Struts2(一)——基本使用
  • 原文地址:https://www.cnblogs.com/linxmouse/p/7780840.html
Copyright © 2011-2022 走看看