Created
July 13, 2016 19:44
-
-
Save mzabsky/796483d5fd9e603421d8812bddc5b6a4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Threading; | |
using System.Threading.Tasks; | |
namespace ZabskyNet | |
{ | |
// This code is for demonstration purposes only and is mean to be as simple as possible. Don't use this in production! | |
public enum TaskPriority | |
{ | |
Low, | |
Normal, | |
High | |
} | |
public delegate void CustomThreadPoolTaskMethod(CustomThreadPool pool); | |
public class CustomThreadPoolTask | |
{ | |
public TaskPriority Priority { get; set; } | |
public CustomThreadPoolTaskMethod Method { get; set; } | |
} | |
public class CustomThreadPool | |
{ | |
// This is not a data structures lesson and .Net doesn't have a proper priority queue :) | |
private List<CustomThreadPoolTask> _tasks = new List<CustomThreadPoolTask>(); | |
public CustomThreadPool(int numberOfThreads) | |
{ | |
for (int i = 0; i < numberOfThreads; i++) | |
{ | |
Thread thread = new Thread(this.PooledThreadBody); | |
thread.Start(); | |
} | |
} | |
public void EnqueueTask(CustomThreadPoolTask task) | |
{ | |
lock (_tasks) | |
{ | |
_tasks.Add(task); | |
} | |
} | |
private void PooledThreadBody() | |
{ | |
while (true) | |
{ | |
// Grab first scheduled task of the highest priority in the "queue" | |
CustomThreadPoolTask taskToExecute; | |
lock (_tasks) | |
{ | |
// Fortunately, IEnumerable OrderBy is stable. | |
taskToExecute = this._tasks.OrderBy(p => (int)p.Priority).FirstOrDefault(); | |
// There are no scheduled tasks, currently. | |
if (taskToExecute == null) | |
{ | |
// Try again in a moment. | |
Thread.Sleep(TimeSpan.FromSeconds(0.1)); | |
continue; | |
} | |
_tasks.Remove(taskToExecute); | |
} | |
SynchronizationContext.SetSynchronizationContext( | |
new CustomThreadPoolSynchronizationContext(this, taskToExecute.Priority) | |
); | |
taskToExecute.Method(this); | |
} | |
} | |
} | |
internal class CustomThreadPoolSynchronizationContext : SynchronizationContext | |
{ | |
private readonly CustomThreadPool _threadPool; | |
private readonly TaskPriority _priority; | |
public CustomThreadPoolSynchronizationContext(CustomThreadPool threadPool, TaskPriority priority) | |
{ | |
_threadPool = threadPool; | |
_priority = priority; | |
} | |
public override SynchronizationContext CreateCopy() | |
{ | |
return new CustomThreadPoolSynchronizationContext(_threadPool, _priority); | |
} | |
public override void Post(SendOrPostCallback d, object state) | |
{ | |
_threadPool.EnqueueTask(new CustomThreadPoolTask | |
{ | |
Method = (pool) => d(state), | |
Priority = _priority | |
}); | |
} | |
} | |
class Program | |
{ | |
static void Main(string[] args) | |
{ | |
var threadPool = new CustomThreadPool(2); | |
for (int i = 0; i < 10; i++) | |
{ | |
var currentI = i; // Make sure correct I gets captured in the lambda | |
threadPool.EnqueueTask(new CustomThreadPoolTask | |
{ | |
Method = async (pool) => | |
{ | |
Console.WriteLine("Task " + currentI + "A started " + Thread.CurrentThread.ManagedThreadId); | |
await Task.Delay(TimeSpan.FromSeconds(3)); | |
Console.WriteLine("Task " + currentI + "A continued " + Thread.CurrentThread.ManagedThreadId); | |
pool.EnqueueTask(new CustomThreadPoolTask | |
{ | |
Method = async (pool2) => | |
{ | |
Console.WriteLine("Task " + currentI + "B started " + Thread.CurrentThread.ManagedThreadId); | |
await Task.Delay(TimeSpan.FromSeconds(3)); | |
Console.WriteLine("Task " + currentI + "B continued " + Thread.CurrentThread.ManagedThreadId); | |
} | |
}); | |
} | |
}); | |
} | |
Console.ReadKey(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment