add all
This commit is contained in:
@@ -0,0 +1,85 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Best.HTTP.Shared.PlatformSupport.Threading
|
||||
{
|
||||
public static class CustomThreadPool
|
||||
{
|
||||
public static int BackgroundThreads => activeThreads;
|
||||
|
||||
private static int minThreads = 1;
|
||||
private static int maxThreads = 128;
|
||||
|
||||
private static int activeThreads = 0;
|
||||
private static int workingThreads = 0;
|
||||
|
||||
private static ConcurrentQueue<Action> jobQueue = new();
|
||||
private static AutoResetEvent are = new (false);
|
||||
|
||||
//private static List<Thread> threads = new();
|
||||
|
||||
public static void SetMinMaxThreads(int min, int max)
|
||||
{
|
||||
minThreads = min;
|
||||
maxThreads = max;
|
||||
}
|
||||
|
||||
public static void QueueUserWorkItem(Action job)
|
||||
{
|
||||
jobQueue.Enqueue(job);
|
||||
are.Set();
|
||||
|
||||
if (workingThreads >= (activeThreads * 0.7f) && activeThreads < maxThreads)
|
||||
{
|
||||
var id = Interlocked.Increment(ref activeThreads);
|
||||
|
||||
var thread = new Thread(ThreadFunc);
|
||||
thread.Name = $"{nameof(CustomThreadPool)}({id})";
|
||||
|
||||
thread.Priority = ThreadPriority.AboveNormal;
|
||||
thread.IsBackground = true;
|
||||
thread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private static void ThreadFunc()
|
||||
{
|
||||
DateTime lastJobProcessed = DateTime.UtcNow;
|
||||
|
||||
using var _ = new ThreadedRunner.IncDecLongLiving(true);
|
||||
|
||||
try
|
||||
{
|
||||
var hasWork = false;
|
||||
do
|
||||
{
|
||||
while (jobQueue.TryDequeue(out var job))
|
||||
{
|
||||
try
|
||||
{
|
||||
Interlocked.Increment(ref workingThreads);
|
||||
lastJobProcessed = DateTime.UtcNow;
|
||||
job?.Invoke();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
UnityEngine.Debug.LogException(e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
Interlocked.Decrement(ref workingThreads);
|
||||
}
|
||||
}
|
||||
|
||||
hasWork = are.WaitOne(TimeSpan.FromSeconds(5));
|
||||
} while (hasWork && DateTime.UtcNow - lastJobProcessed < TimeSpan.FromSeconds(60));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Interlocked.Decrement(ref activeThreads);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c912644eb3bc48eaa2720bf5c63c5e8d
|
||||
timeCreated: 1747129961
|
||||
@@ -0,0 +1,46 @@
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Best.HTTP.Shared.PlatformSupport.Threading
|
||||
{
|
||||
public struct ReadLock : IDisposable
|
||||
{
|
||||
private ReaderWriterLockSlim rwLock;
|
||||
private bool locked;
|
||||
public ReadLock(ReaderWriterLockSlim rwLock)
|
||||
{
|
||||
this.rwLock = rwLock;
|
||||
|
||||
this.locked = this.rwLock.IsReadLockHeld;
|
||||
if (!this.locked)
|
||||
this.rwLock.EnterReadLock();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!this.locked)
|
||||
this.rwLock.ExitReadLock();
|
||||
}
|
||||
}
|
||||
|
||||
public struct WriteLock : IDisposable
|
||||
{
|
||||
private ReaderWriterLockSlim rwLock;
|
||||
private bool locked;
|
||||
|
||||
public WriteLock(ReaderWriterLockSlim rwLock)
|
||||
{
|
||||
this.rwLock = rwLock;
|
||||
this.locked = rwLock.IsWriteLockHeld;
|
||||
|
||||
if (!locked)
|
||||
this.rwLock.EnterWriteLock();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (!locked)
|
||||
this.rwLock.ExitWriteLock();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dd25c801571339740b2046ea34732f17
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,165 @@
|
||||
#define _USE_CUSTOM_THREADPOOL
|
||||
using System;
|
||||
using System.Threading;
|
||||
|
||||
namespace Best.HTTP.Shared.PlatformSupport.Threading
|
||||
{
|
||||
[IL2CPP.Il2CppEagerStaticClassConstruction]
|
||||
public static class ThreadedRunner
|
||||
{
|
||||
public static int ShortLivingThreads { get => _shortLivingThreads; }
|
||||
private static int _shortLivingThreads;
|
||||
|
||||
public static int LongLivingThreads { get => _LongLivingThreads; }
|
||||
private static int _LongLivingThreads;
|
||||
|
||||
public static void SetThreadName(string name)
|
||||
{
|
||||
try
|
||||
{
|
||||
System.Threading.Thread.CurrentThread.Name = name;
|
||||
}
|
||||
catch(Exception ex)
|
||||
{
|
||||
if (HTTPManager.Logger.IsDiagnostic)
|
||||
HTTPManager.Logger.Exception(nameof(ThreadedRunner), nameof(SetThreadName), ex);
|
||||
}
|
||||
}
|
||||
|
||||
public static void RunShortLiving<T>(Action<T> job, T param)
|
||||
{
|
||||
#if USE_CUSTOM_THREADPOOL
|
||||
CustomThreadPool.QueueUserWorkItem(() =>
|
||||
#else
|
||||
ThreadPool.QueueUserWorkItem((state) =>
|
||||
#endif
|
||||
{
|
||||
using var __ = new IncDecShortLiving(true);
|
||||
job(param);
|
||||
});
|
||||
}
|
||||
|
||||
public static void RunShortLiving<T1, T2>(Action<T1, T2> job, T1 param1, T2 param2)
|
||||
{
|
||||
#if USE_CUSTOM_THREADPOOL
|
||||
CustomThreadPool.QueueUserWorkItem(() =>
|
||||
#else
|
||||
ThreadPool.QueueUserWorkItem((state) =>
|
||||
#endif
|
||||
{
|
||||
using var __ = new IncDecShortLiving(true);
|
||||
job(param1, param2);
|
||||
});
|
||||
}
|
||||
|
||||
public static void RunShortLiving<T1, T2, T3>(Action<T1, T2, T3> job, T1 param1, T2 param2, T3 param3)
|
||||
{
|
||||
#if USE_CUSTOM_THREADPOOL
|
||||
CustomThreadPool.QueueUserWorkItem(() =>
|
||||
#else
|
||||
ThreadPool.QueueUserWorkItem((state) =>
|
||||
#endif
|
||||
{
|
||||
using var __ = new IncDecShortLiving(true);
|
||||
job(param1, param2, param3);
|
||||
});
|
||||
}
|
||||
|
||||
public static void RunShortLiving<T1, T2, T3, T4>(Action<T1, T2, T3, T4> job, T1 param1, T2 param2, T3 param3, T4 param4)
|
||||
{
|
||||
#if USE_CUSTOM_THREADPOOL
|
||||
CustomThreadPool.QueueUserWorkItem(() =>
|
||||
#else
|
||||
ThreadPool.QueueUserWorkItem((state) =>
|
||||
#endif
|
||||
{
|
||||
using var __ = new IncDecShortLiving(true);
|
||||
job(param1, param2, param3, param4);
|
||||
});
|
||||
}
|
||||
|
||||
public static void RunShortLiving(Action job)
|
||||
{
|
||||
#if USE_CUSTOM_THREADPOOL
|
||||
CustomThreadPool.QueueUserWorkItem(() =>
|
||||
#else
|
||||
ThreadPool.QueueUserWorkItem((state) =>
|
||||
#endif
|
||||
{
|
||||
using var __ = new IncDecShortLiving(true);
|
||||
job();
|
||||
});
|
||||
}
|
||||
|
||||
public static Thread RunLongLiving(Action job)
|
||||
{
|
||||
var thread = new Thread(() =>
|
||||
{
|
||||
using var __ = new IncDecLongLiving(true);
|
||||
job();
|
||||
});
|
||||
thread.IsBackground = true;
|
||||
thread.Start();
|
||||
|
||||
return thread;
|
||||
}
|
||||
|
||||
private static int maxLongLiving;
|
||||
private static int maxShortLiving;
|
||||
|
||||
public static void StoreLongLivingThreadUsage(int count)
|
||||
{
|
||||
int current;
|
||||
do
|
||||
{
|
||||
current = maxLongLiving;
|
||||
} while (current < count && Interlocked.CompareExchange(ref maxLongLiving, count, current) != current);
|
||||
}
|
||||
|
||||
public static int GetAndZeroLongLivingThreadUsage()
|
||||
{
|
||||
int current = maxLongLiving;
|
||||
Interlocked.Exchange(ref maxLongLiving, 0);
|
||||
return current;
|
||||
}
|
||||
|
||||
public static int GetAndZeroShortLivingThreadUsage()
|
||||
{
|
||||
int current = maxShortLiving;
|
||||
Interlocked.Exchange(ref maxShortLiving, 0);
|
||||
return current;
|
||||
}
|
||||
|
||||
|
||||
public static void StoreShortLivingThreadUsage(int count)
|
||||
{
|
||||
int current;
|
||||
do
|
||||
{
|
||||
current = maxShortLiving;
|
||||
} while (current < count && Interlocked.CompareExchange(ref maxShortLiving, count, current) != current);
|
||||
}
|
||||
|
||||
public struct IncDecShortLiving : IDisposable
|
||||
{
|
||||
public IncDecShortLiving(bool dummy) => Interlocked.Increment(ref ThreadedRunner._shortLivingThreads);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
StoreShortLivingThreadUsage(ThreadedRunner._shortLivingThreads);
|
||||
Interlocked.Decrement(ref ThreadedRunner._shortLivingThreads);
|
||||
}
|
||||
}
|
||||
|
||||
public struct IncDecLongLiving : IDisposable
|
||||
{
|
||||
public IncDecLongLiving(bool dummy) => Interlocked.Increment(ref ThreadedRunner._LongLivingThreads);
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
StoreLongLivingThreadUsage(ThreadedRunner._LongLivingThreads);
|
||||
Interlocked.Decrement(ref ThreadedRunner._LongLivingThreads);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b5b50a35890b2c64c9a36d487c2ca287
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user