// Runs the entire queue until the object is destroyed. // On each try, all the tasks will be executed. If one // task is not -at least- executed, a dummy "Blink" // operation will run. private async void RunQueue() { XDebug debugger = new XDebug("Support", this, $"RunQueue()", debug); debugger.Start(); bool ranLoop; try { while (this != null && gameObject != null) { ranLoop = false; while (tasks.TryDequeue(out Func <Task> task)) { ranLoop = true; await task(); } if (!ranLoop) { await Tasks.Blink(); } } } finally { debugger.End(); } }
/// <summary> /// Queues a task-returning function to be executed /// in the queue processing. The returned result is /// another task that must be waited for. This new /// task is resolved when the function executes in /// its turn in the execution queue. /// </summary> /// <param name="task">The function to queue for execution</param> /// <returns>A task to be waited for, or null if either the task function is null or the current object is destroyed</returns> public Task Queue(Func <Task> task) { // Generate a new ID for debugging. ulong id = taskId++; XDebug debugger = new XDebug("Support", this, $"Queue(() => Task #{id})", debug); debugger.Start(); // Remember: It is FORBIDDEN to check for gameObject property. if (task == null || !this) { debugger.Info($"Returning a finished task for (null task?, this, gameObject) = ({task == null}, {this}, {gameObject})"); debugger.End(); return(Task.CompletedTask); } TaskCompletionSource <bool> source = new TaskCompletionSource <bool>(); debugger.Info($"Queuing task ${id}"); tasks.Enqueue(async() => { XDebug debugger2 = new XDebug("Support", this, $"Queue(() => Task #{id})::Body", debug); debugger2.Start(); try { await task(); source.SetResult(true); } catch (Exception e) { debugger2.Exception(e); source.SetException(e); } finally { debugger2.End(); } }); debugger.End(); return(source.Task); }