csharp-sdk-upm/Storage/Source/Internal/Dispatcher/Unity/UnityDispatcher.cs

103 lines
3.3 KiB
C#

using System;
using System.Collections;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
namespace LeanCloud.Storage.Internal
{
/// <summary>
/// This class represents the internal Unity dispatcher used by the LeanCloud SDK.
///
/// It should be initialized once in your game, usually via AVInitializeBehavior.
///
/// In certain, advanced use-cases, you may wish to use
/// this to set up your dispatcher manually.
/// </summary>
// TODO: (richardross) Review this interface before going public.
public sealed class Dispatcher
{
static Dispatcher()
{
Instance = new Dispatcher();
}
private Dispatcher()
{
DispatcherCoroutine = CreateDispatcherCoroutine();
}
public static Dispatcher Instance { get; private set; }
public GameObject GameObject { get; set; }
public IEnumerator DispatcherCoroutine { get; private set; }
private readonly ReaderWriterLockSlim dispatchQueueLock = new ReaderWriterLockSlim();
private readonly Queue<Action> dispatchQueue = new Queue<Action>();
public void Post(Action action)
{
if (dispatchQueueLock.IsWriteLockHeld)
{
dispatchQueue.Enqueue(action);
return;
}
dispatchQueueLock.EnterWriteLock();
try
{
dispatchQueue.Enqueue(action);
}
finally
{
dispatchQueueLock.ExitWriteLock();
}
}
private IEnumerator CreateDispatcherCoroutine()
{
// We must stop the first invocation here, so that we don't actually do anything until we begin looping.
yield return null;
while (true)
{
dispatchQueueLock.EnterUpgradeableReadLock();
try
{
// We'll only empty what's already in the dispatch queue in this iteration (so that a
// nested dispatch behaves like nextTick()).
int count = dispatchQueue.Count;
if (count > 0)
{
dispatchQueueLock.EnterWriteLock();
try
{
while (count > 0)
{
try
{
dispatchQueue.Dequeue()();
}
catch (Exception e)
{
// If an exception occurs, catch it and log it so that dispatches aren't broken.
Debug.LogException(e);
}
count--;
}
}
finally
{
dispatchQueueLock.ExitWriteLock();
}
}
}
finally
{
dispatchQueueLock.ExitUpgradeableReadLock();
}
yield return null;
}
}
}
}