(61d00a474) v0.9.7.1
This commit is contained in:
@@ -0,0 +1,232 @@
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace GameAnalyticsSDK.Net.Threading
|
||||
{
|
||||
internal class PriorityQueue<TPriority, TItem>
|
||||
{
|
||||
readonly SortedDictionary<TPriority, Queue<TItem>> _subqueues;
|
||||
|
||||
public PriorityQueue(IComparer<TPriority> priorityComparer)
|
||||
{
|
||||
_subqueues = new SortedDictionary<TPriority, Queue<TItem>>(priorityComparer);
|
||||
}
|
||||
|
||||
public PriorityQueue() : this(Comparer<TPriority>.Default) { }
|
||||
|
||||
public void Enqueue(TPriority priority, TItem item)
|
||||
{
|
||||
if (!_subqueues.ContainsKey(priority))
|
||||
{
|
||||
AddQueueOfPriority(priority);
|
||||
}
|
||||
|
||||
_subqueues[priority].Enqueue(item);
|
||||
}
|
||||
|
||||
private void AddQueueOfPriority(TPriority priority)
|
||||
{
|
||||
_subqueues.Add(priority, new Queue<TItem>());
|
||||
}
|
||||
|
||||
public TItem Peek()
|
||||
{
|
||||
if (HasItems)
|
||||
return _subqueues.First().Value.Peek();
|
||||
else
|
||||
throw new InvalidOperationException("The queue is empty");
|
||||
}
|
||||
|
||||
public bool HasItems
|
||||
{
|
||||
get { return _subqueues.Any(); }
|
||||
}
|
||||
|
||||
public TItem Dequeue()
|
||||
{
|
||||
if (_subqueues.Any())
|
||||
return DequeueFromHighPriorityQueue();
|
||||
else
|
||||
throw new InvalidOperationException("The queue is empty");
|
||||
}
|
||||
|
||||
private TItem DequeueFromHighPriorityQueue()
|
||||
{
|
||||
KeyValuePair<TPriority, Queue<TItem>> first = _subqueues.First();
|
||||
TItem nextItem = first.Value.Dequeue();
|
||||
if (!first.Value.Any())
|
||||
{
|
||||
_subqueues.Remove(first.Key);
|
||||
}
|
||||
return nextItem;
|
||||
}
|
||||
|
||||
public int Count
|
||||
{
|
||||
get { return _subqueues.Sum(q => q.Value.Count); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
using System;
|
||||
|
||||
namespace GameAnalyticsSDK.Net
|
||||
{
|
||||
internal class TimedBlock : IComparable<TimedBlock>
|
||||
{
|
||||
public readonly DateTime deadline;
|
||||
public readonly Action block;
|
||||
public readonly string blockName;
|
||||
|
||||
public TimedBlock (DateTime deadline, Action block, string blockName)
|
||||
{
|
||||
this.deadline = deadline;
|
||||
this.block = block;
|
||||
this.blockName = blockName;
|
||||
}
|
||||
|
||||
public int CompareTo(TimedBlock other)
|
||||
{
|
||||
return this.deadline.CompareTo (other.deadline);
|
||||
}
|
||||
|
||||
public override string ToString ()
|
||||
{
|
||||
return "{TimedBlock: deadLine=" + this.deadline.Ticks + ", block=" + this.blockName + "}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user