Why doesn't std.Thread.Pool pass its allocator to std.Thread.spawn()?

Currently, std.Thread.Pool.init() spawn its threads with the following code:

    for (pool.threads) |*thread| {
        thread.* = try std.Thread.spawn(.{}, worker, .{pool});
        spawned += 1;
    }

For WASM, this would lead to a compilation failure since WebAssembly threads need an allocator. Given that std.Thread.Pool.init() requires an allocator, why doesn’t it just pass it on?

Am I missing something?
Do you pass the std.heap.wasm_allocator in Pool.init?
Example:

    var pool: Pool = undefined;
    try pool.init(.{
        .allocator = std.heap.wasm_allocator,
    });
    defer pool.deinit();

You pass the allocator to Pool, but Pool is currently not using during the spawning of the worker threads.
I think @chung-leong is right, there’s no reason not the pass the pool allocator in the SpawnConfig parameter.
This should be a simple PR.

std.Thread.spawn is not the correct API.

Threads that go into the Pool are created using the std.Thread.Pool.spawn or the other methods of the Pool.

Doesn’t the std.Thread.Pool.spawn function just submit work to the thread pool and the actual thread creation is in std.Thread.Pool.init method?

for (pool.threads) |*thread| {
        thread.* = try std.Thread.spawn(.{}, worker, .{pool});
        spawned += 1;
    }

Yes, std.Thread.Pool.spawn takes care to pass the pool worker and the pool as parameter, the allocator is stored in the pool and used by worker to create and destroy a closure.
But if someone calls std.Thread.spawn directly, the thread is not associated with any pool and does not need an allocator.

But, as shown in the snippet, the Pool.init method is calling Thread.spawn directly, right? In order for this method to use the allocator, the pool would have to pass it in the SpawnConfig parameter.

Oh! That is what I was missing.

You are right. This is a bug.

1 Like