diff options
| author | Jake Mannens <jake@asger.xyz> | 2023-09-27 03:38:58 +1000 |
|---|---|---|
| committer | Jake Mannens <jake@asger.xyz> | 2023-09-27 03:38:58 +1000 |
| commit | bc82b2dc2f7405c0fd4d179830412ea8209137b1 (patch) | |
| tree | 26fdaa8635a1487e3ae9fd112336be8df0f723ec /Util/LimitedConcurrencyTaskScheduler.cs | |
| parent | 39eead0052215d7be4f49906e987fef7fb0c700b (diff) | |
Added MemoryCache class and implemented principal/ACL cache in the security service
Diffstat (limited to 'Util/LimitedConcurrencyTaskScheduler.cs')
| -rw-r--r-- | Util/LimitedConcurrencyTaskScheduler.cs | 88 |
1 files changed, 88 insertions, 0 deletions
diff --git a/Util/LimitedConcurrencyTaskScheduler.cs b/Util/LimitedConcurrencyTaskScheduler.cs new file mode 100644 index 0000000..8d5adf2 --- /dev/null +++ b/Util/LimitedConcurrencyTaskScheduler.cs @@ -0,0 +1,88 @@ +namespace HyperBooru.Util; + +public class LimitedConcurrencyTaskScheduler : TaskScheduler { + public sealed override int MaximumConcurrencyLevel => + maxConcurrency; + + private int maxConcurrency; + + [ThreadStatic] + private static bool threadIsProcessingItems; + + private readonly LinkedList<Task> tasks = new(); + + private int delegatesQueuedOrRunning = 0; + + public LimitedConcurrencyTaskScheduler() { + maxConcurrency = Environment.ProcessorCount; + } + + public LimitedConcurrencyTaskScheduler(int maxConcurrency) { + if(maxConcurrency < 1) + throw new ArgumentOutOfRangeException("maxConcurrency must be greater than 0"); + this.maxConcurrency = (int) maxConcurrency; + } + + protected sealed override void QueueTask(Task task) { + lock(tasks) { + tasks.AddLast(task); + if(delegatesQueuedOrRunning < maxConcurrency) { + delegatesQueuedOrRunning++; + NotifyThreadPoolOfPendingWork(); + } + } + } + + private void NotifyThreadPoolOfPendingWork() { + ThreadPool.UnsafeQueueUserWorkItem(_ => { + threadIsProcessingItems = true; + try { + while(true) { + Task item; + lock(tasks) { + if(tasks.Count == 0) { + delegatesQueuedOrRunning--; + break; + } else { + item = tasks.First.Value; + tasks.RemoveFirst(); + } + } + TryExecuteTask(item); + } + } finally { + threadIsProcessingItems = false; + } + }, null); + } + + protected sealed override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) { + if(!threadIsProcessingItems) + return false; + + if(taskWasPreviouslyQueued) + return TryDequeue(task) ? TryExecuteTask(task) : false; + else + return TryExecuteTask(task); + } + + protected sealed override bool TryDequeue(Task task) { + lock(tasks) { + return tasks.Remove(task); + } + } + + protected sealed override IEnumerable<Task> GetScheduledTasks() { + bool lockTaken = false; + try { + Monitor.TryEnter(tasks, ref lockTaken); + if(lockTaken) + return tasks; + else + throw new NotSupportedException(); + } finally { + if(lockTaken) + Monitor.Exit(tasks); + } + } +} |
