Files
LuaCsForBarotraumaEP/Libraries/GameAnalytics/GA-SDK-MONO-SHARED/Threading/GAThreading.cs
2020-03-04 13:04:10 +01:00

233 lines
5.8 KiB
C#

using System;
using System.Collections.Generic;
#if WINDOWS_WSA || WINDOWS_UWP
using Windows.System.Threading;
using Windows.Foundation;
using System.Threading.Tasks;
#else
using System.Threading;
#endif
using GameAnalyticsSDK.Net.Logging;
namespace GameAnalyticsSDK.Net.Threading
{
public class GAThreading
{
private static bool endThread = false;
private static DateTime threadDeadline;
private static readonly GAThreading _instance = new GAThreading ();
private const int ThreadWaitTimeInMs = 1000;
private readonly PriorityQueue<long, TimedBlock> blocks = new PriorityQueue<long, TimedBlock>();
private readonly object threadLock = new object();
private TimedBlock scheduledBlock;
private bool hasScheduledBlockRun;
#if WINDOWS_WSA || WINDOWS_UWP
private IAsyncAction thread;
#else
private Thread thread;
#endif
private GAThreading()
{
threadDeadline = DateTime.Now;
hasScheduledBlockRun = true;
}
~GAThreading()
{
StopThread();
}
private static GAThreading Instance
{
get
{
return _instance;
}
}
private static void RunBlocks()
{
TimedBlock timedBlock;
while ((timedBlock = GetNextBlock()) != null)
{
timedBlock.block();
}
if ((timedBlock = GetScheduledBlock()) != null)
{
timedBlock.block();
}
}
public static void Run()
{
GALogger.D("Starting GA thread");
try
{
while(!endThread && threadDeadline.CompareTo(DateTime.Now) > 0)
{
RunBlocks();
#if WINDOWS_WSA || WINDOWS_UWP
Task.Delay(ThreadWaitTimeInMs).Wait();
#else
Thread.Sleep(ThreadWaitTimeInMs);
#endif
}
// run any last blocks added
RunBlocks();
if (!endThread)
{
GALogger.D("Ending GA thread");
}
}
catch(Exception)
{
//GALogger.E("Error on GA thread");
//GALogger.E(e.ToString());
}
}
public static void PerformTaskOnGAThread(string blockName, Action taskBlock)
{
PerformTaskOnGAThread(blockName, taskBlock, 0);
}
public static void PerformTaskOnGAThread(string blockName, Action taskBlock, long delayInSeconds)
{
if(endThread)
{
return;
}
lock(Instance.threadLock)
{
DateTime time = DateTime.Now;
time = time.AddSeconds(delayInSeconds);
TimedBlock timedBlock = new TimedBlock(time, taskBlock, blockName);
Instance.AddTimedBlock(timedBlock);
threadDeadline = time.AddSeconds(10);
#if WINDOWS_WSA || WINDOWS_UWP
if (IsThreadFinished())
{
StartThread();
}
#else
if (IsThreadFinished())
{
if(Instance.thread != null)
{
Instance.thread.Join();
}
StartThread();
}
#endif
}
}
public static void ScheduleTimer(double interval, string blockName, Action callback)
{
if (endThread)
{
return;
}
lock (Instance.threadLock)
{
if(Instance.hasScheduledBlockRun)
{
DateTime time = DateTime.Now;
time = time.AddSeconds(interval);
Instance.scheduledBlock = new TimedBlock(time, callback, blockName);
Instance.hasScheduledBlockRun = false;
threadDeadline = time.AddSeconds(2);
#if WINDOWS_WSA || WINDOWS_UWP
if (IsThreadFinished())
{
StartThread();
}
#else
if (IsThreadFinished())
{
if(Instance.thread != null)
{
Instance.thread.Join();
}
StartThread();
}
#endif
}
}
}
private void AddTimedBlock(TimedBlock timedBlock)
{
this.blocks.Enqueue(timedBlock.deadline.Ticks, timedBlock);
}
private static TimedBlock GetNextBlock()
{
lock(Instance.threadLock)
{
DateTime now = DateTime.Now;
if(Instance.blocks.HasItems && Instance.blocks.Peek().deadline.CompareTo(now) <= 0)
{
return Instance.blocks.Dequeue();
}
return null;
}
}
private static TimedBlock GetScheduledBlock()
{
lock (Instance.threadLock)
{
DateTime now = DateTime.Now;
if (!Instance.hasScheduledBlockRun && Instance.scheduledBlock != null && Instance.scheduledBlock.deadline.CompareTo(now) <= 0)
{
Instance.hasScheduledBlockRun = true;
return Instance.scheduledBlock;
}
return null;
}
}
public static void StartThread()
{
#if WINDOWS_WSA || WINDOWS_UWP
Instance.thread = ThreadPool.RunAsync(o => Run());
#else
Instance.thread = new Thread(new ThreadStart(Run));
Instance.thread.Priority = ThreadPriority.Lowest;
Instance.thread.Start();
#endif
}
public static void StopThread()
{
endThread = true;
}
public static bool IsThreadFinished()
{
#if WINDOWS_WSA || WINDOWS_UWP
return Instance.thread == null || Instance.thread.Status != AsyncStatus.Started;
#else
return Instance.thread == null || !Instance.thread.IsAlive;
#endif
}
}
}