123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- /**
- * Copyright(c) Live2D Inc. All rights reserved.
- *
- * Use of this source code is governed by the Live2D Open Software license
- * that can be found at https://www.live2d.com/eula/live2d-open-software-license-agreement_en.html.
- */
- using Live2D.Cubism.Core;
- using System.Collections.Generic;
- using System.Threading;
- using UnityEngine;
- namespace Live2D.Cubism.Framework.Tasking
- {
- /// <summary>
- /// Built-in task handler, works async.
- /// </summary>
- public static class CubismBuiltinAsyncTaskHandler
- {
- #region Workers
- /// <summary>
- /// <see cref="ICubismTask"/>s waiting for execution.
- /// </summary>
- private static Queue<ICubismTask> Tasks { get; set; }
- /// <summary>
- /// Background worker threads.
- /// </summary>
- private static Thread Worker { get; set; }
- /// <summary>
- /// Lock for syncing access to <see cref="Tasks"/> and <see cref="CallItADay"/>.
- /// </summary>
- private static object Lock { get; set; }
- /// <summary>
- /// Signal for waking up workers.
- /// </summary>
- private static ManualResetEvent Signal { get; set; }
- /// <summary>
- /// <see cref="CallItADay"/> backing field. ALWAYS ACCESS THROUGH PROPERTY!
- /// </summary>
- private static bool _callItADay;
- /// <summary>
- /// True if workers should exit.
- /// </summary>
- private static bool CallItADay
- {
- get
- {
- lock (Lock)
- {
- return _callItADay;
- }
- }
- set
- {
- lock (Lock)
- {
- _callItADay = value;
- }
- }
- }
- /// <summary>
- /// Initializes async task handling.
- /// </summary>
- public static void Activate()
- {
- // Check if it is already set.
- if (CubismTaskQueue.OnTask != null && CubismTaskQueue.OnTask != EnqueueTask)
- {
- Debug.LogWarning("\"CubismTaskQueue.OnTask\" already set.");
- return;
- }
- // Initialize fields.
- Tasks = new Queue<ICubismTask>();
- Worker = new Thread(Work);
- Lock = new object();
- Signal = new ManualResetEvent(false);
- CallItADay = false;
- // Become handler.
- CubismTaskQueue.OnTask = EnqueueTask;
- // Start worker.
- Worker.Start();
- }
- /// <summary>
- /// Cleanup workers.
- /// </summary>
- public static void Deactivate()
- {
- // Return early if self isn' handler.
- if (CubismTaskQueue.OnTask != EnqueueTask)
- {
- return;
- }
- // Unbecome handler.
- CubismTaskQueue.OnTask = null;
- // Stop worker.
- CallItADay = true;
- if (Worker != null)
- {
- Signal.Set();
- Worker.Join();
- }
- // Reset fields
- Tasks = null;
- Worker = null;
- Lock = null;
- Signal = null;
- }
- /// <summary>
- /// Enqueues a new task.
- /// </summary>
- /// <param name="task">Task to enqueue.</param>
- private static void EnqueueTask(ICubismTask task)
- {
- lock (Lock)
- {
- Tasks.Enqueue(task);
- Signal.Set();
- }
- }
- /// <summary>
- /// Dequeues a task.
- /// </summary>
- /// <returns>A valid task on success; <see langword="null"/> otherwise.</returns>
- private static ICubismTask DequeueTask()
- {
- lock (Lock)
- {
- return (Tasks.Count > 0)
- ? Tasks.Dequeue()
- : null;
- }
- }
- /// <summary>
- /// Entry point for workers.
- /// </summary>
- private static void Work()
- {
- while (!CallItADay)
- {
- // Try to dequeue a task.
- var task = DequeueTask();
- // Execute task if available.
- if (task != null)
- {
- task.Execute();
- }
- // Wait for a task to become available.
- else
- {
- Signal.WaitOne();
- Signal.Reset();
- }
- }
- }
- #endregion
- }
- }
|