Skip to content

NTDLS.DelegateThreadPooling Usage

A predictable active thread pool where work items are queued as delegates and you control the pool size.

Published Jul 25, 2026

NTDLS.DelegateThreadPooling

What it is. A high-performance, predictable active thread pool for C#. Work items are queued as delegate functions, and unlike System.Threading.ThreadPool you have total control over the pool size, can enforce queue limits, wait on collections of items to complete, and run multiple independent pools so different workloads do not interfere with one another.

When to reach for it. You need background workers with known concurrency - batch processing, file work, outbound calls - and you want to block until a set of jobs finishes without wiring up your own Task.WhenAll gymnastics. Skip it if you are happy with Task.Run and the ambient thread pool; this library earns its keep when predictability and isolation between workloads matter.

Getting started

Create a pool with a fixed worker count, then enqueue delegates:

private static readonly DelegateThreadPool _pool = new(10);

static void Main()
{
    var itemStates = new List<QueueItemState<object>>();

    // Enqueue 100 work items as delegate functions.
    for (int i = 0; i < 100; i++)
    {
        int jobNumber = i;
        var state = _pool.Enqueue(() =>
        {
            // Do some work...
            Thread.Sleep(100); 
        });

        itemStates.Add(state);
    }

    // Wait on all of the work items to complete.
    itemStates.ForEach(t => t.WaitForCompletion());

    Console.WriteLine("All workers are complete.");

    _pool.Dispose();
}

Each Enqueue returns a QueueItemState<T> you can hold onto and wait on individually. If you would rather wait on everything at once, use a child pool:

var childPool = _pool.CreateChildPool();

for (int i = 0; i < 100; i++)
{
    childPool.Enqueue(() => Thread.Sleep(100)); // Do some work...
}

childPool.WaitForCompletion(); // Blocks until every enqueued item has run.

Child pools let you carve out an isolated workload - say, imports versus exports - while sharing the same underlying worker budget.

NuGet: NTDLS.DelegateThreadPooling

An unhandled error has occurred. Reload 🗙