feature. See also
. The project being documented here (as the example) is the Zig library itself.
Threaded.groupConcurrent
fn groupConcurrent(
userdata: ?*anyopaque,
type_erased: *Io.Group,
context: []const u8,
context_alignment: Alignment,
start: *const fn (context: *const anyopaque) void,
) Io.ConcurrentError!void
File
Code
fn groupConcurrent(
userdata: ?*anyopaque,
type_erased: *Io.Group,
context: []const u8,
context_alignment: Alignment,
start: *const fn (context: *const anyopaque) void,
) Io.ConcurrentError!void {
if (builtin.single_threaded) return error.ConcurrencyUnavailable;
const t: *Threaded = @ptrCast(@alignCast(userdata));
const g: Group = .{ .ptr = type_erased };
const gpa = t.allocator;
const task = Group.Task.create(gpa, g, context, context_alignment, start) catch |err| switch (err) {
error.OutOfMemory => return error.ConcurrencyUnavailable,
};
errdefer task.destroy(gpa);
mutexLock(&t.mutex);
defer mutexUnlock(&t.mutex);
const busy_count = t.busy_count;
if (busy_count >= @backingInt(t.concurrent_limit))
return error.ConcurrencyUnavailable;
t.busy_count = busy_count + 1;
errdefer t.busy_count = busy_count;
const pool_size = t.wait_group.value();
if (pool_size - busy_count == 0) {
t.wait_group.start();
errdefer t.wait_group.finish();
const thread = std.Thread.spawn(.{ .stack_size = t.stack_size }, worker, .{t}) catch
return error.ConcurrencyUnavailable;
thread.detach();
}
// prepend so that the task doesn't finish without observing this and try to decrement the count
// below zero.
_ = g.status().fetchAdd(.{
.num_running = 1,
.have_awaiter = false,
.canceled = false,
}, .monotonic);
t.run_queue.prepend(&task.runnable.node);
condSignal(&t.cond);
}