/**
* 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
{
///
/// Built-in task handler, works async.
///
public static class CubismBuiltinAsyncTaskHandler
{
#region Workers
///
/// s waiting for execution.
///
private static Queue Tasks { get; set; }
///
/// Background worker threads.
///
private static Thread Worker { get; set; }
///
/// Lock for syncing access to and .
///
private static object Lock { get; set; }
///
/// Signal for waking up workers.
///
private static ManualResetEvent Signal { get; set; }
///
/// backing field. ALWAYS ACCESS THROUGH PROPERTY!
///
private static bool _callItADay;
///
/// True if workers should exit.
///
private static bool CallItADay
{
get
{
lock (Lock)
{
return _callItADay;
}
}
set
{
lock (Lock)
{
_callItADay = value;
}
}
}
///
/// Initializes async task handling.
///
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();
Worker = new Thread(Work);
Lock = new object();
Signal = new ManualResetEvent(false);
CallItADay = false;
// Become handler.
CubismTaskQueue.OnTask = EnqueueTask;
// Start worker.
Worker.Start();
}
///
/// Cleanup workers.
///
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;
}
///
/// Enqueues a new task.
///
/// Task to enqueue.
private static void EnqueueTask(ICubismTask task)
{
lock (Lock)
{
Tasks.Enqueue(task);
Signal.Set();
}
}
///
/// Dequeues a task.
///
/// A valid task on success; otherwise.
private static ICubismTask DequeueTask()
{
lock (Lock)
{
return (Tasks.Count > 0)
? Tasks.Dequeue()
: null;
}
}
///
/// Entry point for workers.
///
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
}
}