Lightweight thread pool with back-pressure and zero allocations after initialization.

The standard library's std.Thread.Pool is designed for large jobs. As such, each scheduled job has non-trivial overhead.

var tp = try zul.ThreadPool(someTask).init(allocator, .{.count = 4, .backlog = 500});
defer tp.deinit(allocator);

// This will block if the threadpool has 500 pending jobs
// where 500 is the configured backlog
tp.spawn(.{1, true});


fn someTask(i: i32, allow: bool) void {
	// process
}

zul.ThreadPool(comptime Fn: type) is a simple and memory efficient way to have pre-initialized threads ready to process incoming work. The ThreadPool is a generic and takes the function to execute as a parameter.

fn init(
	// Allocator is used to create the thread pool, no allocations occur after `init` returns.
	allocator: std.mem.Allocator,

	opts: .{
		// number of threads
		.count: u32 = 1,

		// The number of pending jobs to allow before callers are blocked.
		// The library will allocate an array of this size to hold all pending
		// parameters.
		.backlog: u32 = 500,

	}
) !*ThreadPool(Fn)

Creates a zul.ThreadPool(Fn).

This is method thread-safe. The threads will be stopped and cleaned up.

Enqueues the arguments to be processed by Fn in a worker thread. This call blocks if the number of pending jobs has reached its configured backlog.