166 lines
4.1 KiB
C#
166 lines
4.1 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using UnityEngine;
|
|
|
|
namespace AmplifyMotion
|
|
{
|
|
internal class WorkerThreadPool
|
|
{
|
|
private const int ThreadStateQueueCapacity = 1024;
|
|
|
|
internal Queue<MotionState>[] m_threadStateQueues;
|
|
|
|
internal object[] m_threadStateQueueLocks;
|
|
|
|
private int m_threadPoolSize;
|
|
|
|
private ManualResetEvent m_threadPoolTerminateSignal;
|
|
|
|
private AutoResetEvent[] m_threadPoolContinueSignals;
|
|
|
|
private Thread[] m_threadPool;
|
|
|
|
private bool m_threadPoolFallback;
|
|
|
|
internal object m_threadPoolLock;
|
|
|
|
internal int m_threadPoolIndex;
|
|
|
|
internal void InitializeAsyncUpdateThreads(int threadCount, bool systemThreadPool)
|
|
{
|
|
if (systemThreadPool)
|
|
{
|
|
m_threadPoolFallback = true;
|
|
return;
|
|
}
|
|
try
|
|
{
|
|
m_threadPoolSize = threadCount;
|
|
m_threadStateQueues = new Queue<MotionState>[m_threadPoolSize];
|
|
m_threadStateQueueLocks = new object[m_threadPoolSize];
|
|
m_threadPool = new Thread[m_threadPoolSize];
|
|
m_threadPoolTerminateSignal = new ManualResetEvent(false);
|
|
m_threadPoolContinueSignals = new AutoResetEvent[m_threadPoolSize];
|
|
m_threadPoolLock = new object();
|
|
m_threadPoolIndex = 0;
|
|
for (int i = 0; i < m_threadPoolSize; i++)
|
|
{
|
|
m_threadStateQueues[i] = new Queue<MotionState>(1024);
|
|
m_threadStateQueueLocks[i] = new object();
|
|
m_threadPoolContinueSignals[i] = new AutoResetEvent(false);
|
|
m_threadPool[i] = new Thread(AsyncUpdateThread);
|
|
m_threadPool[i].Start(new KeyValuePair<object, int>(this, i));
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
Debug.LogWarning("[AmplifyMotion] Non-critical error while initializing WorkerThreads. Falling back to using System.Threading.ThreadPool().\n" + ex.Message);
|
|
m_threadPoolFallback = true;
|
|
}
|
|
}
|
|
|
|
internal void FinalizeAsyncUpdateThreads()
|
|
{
|
|
if (m_threadPoolFallback)
|
|
{
|
|
return;
|
|
}
|
|
m_threadPoolTerminateSignal.Set();
|
|
for (int i = 0; i < m_threadPoolSize; i++)
|
|
{
|
|
if (m_threadPool[i].ThreadState == ThreadState.Running)
|
|
{
|
|
m_threadPoolContinueSignals[i].Set();
|
|
m_threadPool[i].Join();
|
|
m_threadPool[i] = null;
|
|
}
|
|
lock (m_threadStateQueueLocks[i])
|
|
{
|
|
while (m_threadStateQueues[i].Count > 0)
|
|
{
|
|
m_threadStateQueues[i].Dequeue().AsyncUpdate();
|
|
}
|
|
}
|
|
}
|
|
m_threadStateQueues = null;
|
|
m_threadStateQueueLocks = null;
|
|
m_threadPoolSize = 0;
|
|
m_threadPool = null;
|
|
m_threadPoolTerminateSignal = null;
|
|
m_threadPoolContinueSignals = null;
|
|
m_threadPoolLock = null;
|
|
m_threadPoolIndex = 0;
|
|
}
|
|
|
|
internal void EnqueueAsyncUpdate(MotionState state)
|
|
{
|
|
if (!m_threadPoolFallback)
|
|
{
|
|
lock (m_threadStateQueueLocks[m_threadPoolIndex])
|
|
{
|
|
m_threadStateQueues[m_threadPoolIndex].Enqueue(state);
|
|
}
|
|
m_threadPoolContinueSignals[m_threadPoolIndex].Set();
|
|
m_threadPoolIndex++;
|
|
if (m_threadPoolIndex >= m_threadPoolSize)
|
|
{
|
|
m_threadPoolIndex = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
ThreadPool.QueueUserWorkItem(AsyncUpdateCallback, state);
|
|
}
|
|
}
|
|
|
|
private static void AsyncUpdateCallback(object obj)
|
|
{
|
|
MotionState motionState = (MotionState)obj;
|
|
motionState.AsyncUpdate();
|
|
}
|
|
|
|
private static void AsyncUpdateThread(object obj)
|
|
{
|
|
KeyValuePair<object, int> keyValuePair = (KeyValuePair<object, int>)obj;
|
|
WorkerThreadPool workerThreadPool = (WorkerThreadPool)keyValuePair.Key;
|
|
int value = keyValuePair.Value;
|
|
while (true)
|
|
{
|
|
try
|
|
{
|
|
workerThreadPool.m_threadPoolContinueSignals[value].WaitOne();
|
|
if (workerThreadPool.m_threadPoolTerminateSignal.WaitOne(0))
|
|
{
|
|
break;
|
|
}
|
|
while (true)
|
|
{
|
|
MotionState motionState = null;
|
|
lock (workerThreadPool.m_threadStateQueueLocks[value])
|
|
{
|
|
if (workerThreadPool.m_threadStateQueues[value].Count > 0)
|
|
{
|
|
motionState = workerThreadPool.m_threadStateQueues[value].Dequeue();
|
|
}
|
|
}
|
|
if (motionState != null)
|
|
{
|
|
motionState.AsyncUpdate();
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
if (ex.GetType() != typeof(ThreadAbortException))
|
|
{
|
|
Debug.LogWarning(ex);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|