mirror of https://github.com/Squidex/squidex.git
7 changed files with 74 additions and 248 deletions
@ -1,142 +0,0 @@ |
|||||
// ==========================================================================
|
|
||||
// LimitedConcurrencyLevelTaskScheduler.cs
|
|
||||
// Squidex Headless CMS
|
|
||||
// ==========================================================================
|
|
||||
// Copyright (c) Squidex Group
|
|
||||
// All rights reserved.
|
|
||||
// ==========================================================================
|
|
||||
|
|
||||
using System; |
|
||||
using System.Collections.Generic; |
|
||||
using System.Threading; |
|
||||
using System.Threading.Tasks; |
|
||||
|
|
||||
namespace Squidex.Infrastructure.Tasks |
|
||||
{ |
|
||||
public sealed class LimitedConcurrencyLevelTaskScheduler : TaskScheduler |
|
||||
{ |
|
||||
[ThreadStatic] |
|
||||
private static bool currentThreadIsProcessingItems; |
|
||||
private readonly LinkedList<Task> tasks = new LinkedList<Task>(); |
|
||||
private readonly int maxDegreeOfParallelism; |
|
||||
private int delegatesQueuedOrRunning; |
|
||||
|
|
||||
public override int MaximumConcurrencyLevel |
|
||||
{ |
|
||||
get { return maxDegreeOfParallelism; } |
|
||||
} |
|
||||
|
|
||||
public LimitedConcurrencyLevelTaskScheduler(int maxDegreeOfParallelism) |
|
||||
{ |
|
||||
Guard.GreaterThan(maxDegreeOfParallelism, 0, nameof(maxDegreeOfParallelism)); |
|
||||
|
|
||||
this.maxDegreeOfParallelism = maxDegreeOfParallelism; |
|
||||
} |
|
||||
|
|
||||
protected override void QueueTask(Task task) |
|
||||
{ |
|
||||
lock (tasks) |
|
||||
{ |
|
||||
tasks.AddLast(task); |
|
||||
|
|
||||
if (delegatesQueuedOrRunning < maxDegreeOfParallelism) |
|
||||
{ |
|
||||
++delegatesQueuedOrRunning; |
|
||||
|
|
||||
NotifyThreadPoolOfPendingWork(); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
private void NotifyThreadPoolOfPendingWork() |
|
||||
{ |
|
||||
ThreadPool.UnsafeQueueUserWorkItem(_ => |
|
||||
{ |
|
||||
currentThreadIsProcessingItems = true; |
|
||||
try |
|
||||
{ |
|
||||
while (true) |
|
||||
{ |
|
||||
Task item; |
|
||||
|
|
||||
lock (tasks) |
|
||||
{ |
|
||||
if (tasks.Count == 0) |
|
||||
{ |
|
||||
--delegatesQueuedOrRunning; |
|
||||
break; |
|
||||
} |
|
||||
|
|
||||
item = tasks.First.Value; |
|
||||
|
|
||||
tasks.RemoveFirst(); |
|
||||
} |
|
||||
|
|
||||
TryExecuteTask(item); |
|
||||
} |
|
||||
} |
|
||||
finally |
|
||||
{ |
|
||||
currentThreadIsProcessingItems = false; |
|
||||
} |
|
||||
}, null); |
|
||||
} |
|
||||
|
|
||||
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) |
|
||||
{ |
|
||||
if (!currentThreadIsProcessingItems) |
|
||||
{ |
|
||||
return false; |
|
||||
} |
|
||||
|
|
||||
if (taskWasPreviouslyQueued) |
|
||||
{ |
|
||||
if (TryDequeue(task)) |
|
||||
{ |
|
||||
return TryExecuteTask(task); |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
return false; |
|
||||
} |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
return TryExecuteTask(task); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected override bool TryDequeue(Task task) |
|
||||
{ |
|
||||
lock (tasks) |
|
||||
{ |
|
||||
return tasks.Remove(task); |
|
||||
} |
|
||||
} |
|
||||
|
|
||||
protected override IEnumerable<Task> GetScheduledTasks() |
|
||||
{ |
|
||||
var lockTaken = false; |
|
||||
try |
|
||||
{ |
|
||||
Monitor.TryEnter(tasks, ref lockTaken); |
|
||||
|
|
||||
if (lockTaken) |
|
||||
{ |
|
||||
return tasks; |
|
||||
} |
|
||||
else |
|
||||
{ |
|
||||
throw new NotSupportedException(); |
|
||||
} |
|
||||
} |
|
||||
finally |
|
||||
{ |
|
||||
if (lockTaken) |
|
||||
{ |
|
||||
Monitor.Exit(tasks); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
Loading…
Reference in new issue