pub const Group = struct token: std.atomic.Value(?*anyopaque)This value indicates whether or not a group has pending tasks. null means there are no pending tasks, and no resources associated with the group, so await and cancel return immediately without calling the implementation. This means that token must be accessed atomically to avoid racing with the check in await and cancel.
state: usizeThis value is available for the implementation to use as it wishes.
pub fn async(g: *Group, io: Io, function: anytype, args: std.meta.ArgsTuple(@TypeOf(function))) voidEquivalent to Io.async, except the task is spawned in this Group instead of becoming associated with a Future.
The return type of function must be coercible to Cancelable!void. function returning error.Canceled does nothing because it is an cancelation propagation boundary.
Once this function is called, there are resources associated with the group. To release those resources, await or cancel must eventually be called.
function is not guaranteed to have been called until await or cancel is called.
pub fn concurrent(g: *Group, io: Io, function: anytype, args: std.meta.ArgsTuple(@TypeOf(function))) ConcurrentError!voidEquivalent to Io.concurrent, except the task is spawned in this Group instead of becoming associated with a Future.
The return type of function must be coercible to Cancelable!void. function returning error.Canceled does nothing because it is an cancelation propagation boundary.
Once this function is called, there are resources associated with the group. To release those resources, Group.await or Group.cancel must eventually be called.
pub fn await(g: *Group, io: Io) Cancelable!voidBlocks until all tasks of the group finish. During this time, cancelation requests propagate to all members of the group, and will also cause error.Canceled to be returned when the group does ultimately finish.
After this function returns, all tasks of the Group created with async or concurrent are guaranteed to have run.
Idempotent. Not threadsafe.
It is safe to call this function concurrently with Group.async or Group.concurrent, provided that the group does not complete until the call to Group.async or Group.concurrent returns.
pub fn cancel(g: *Group, io: Io) voidEquivalent to await but immediately requests cancelation on all members of the group.
After this function returns, all tasks of the Group created with async or concurrent are guaranteed to have run.
For a description of cancelation and cancelation points, see Future.cancel.
Idempotent. Not threadsafe.
It is safe to call this function concurrently with Group.async or Group.concurrent, provided that the group does not complete until the call to Group.async or Group.concurrent returns.
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426pub const Group = struct {
/// This value indicates whether or not a group has pending tasks. `null`
/// means there are no pending tasks, and no resources associated with the
/// group, so `await` and `cancel` return immediately without calling the
/// implementation. This means that `token` must be accessed atomically to
/// avoid racing with the check in `await` and `cancel`.
token: std.atomic.Value(?*anyopaque),
/// This value is available for the implementation to use as it wishes.
state: usize,
pub const init: Group = .{ .token = .init(null), .state = 0 };
/// Equivalent to `Io.async`, except the task is spawned in this `Group`
/// instead of becoming associated with a `Future`.
///
/// The return type of `function` must be coercible to `Cancelable!void`.
/// `function` returning `error.Canceled` does nothing because it is an
/// cancelation propagation boundary.
///
/// Once this function is called, there are resources associated with the
/// group. To release those resources, `await` or `cancel` must eventually
/// be called.
///
/// `function` is not guaranteed to have been called until `await` or
/// `cancel` is called.
pub fn async(g: *Group, io: Io, function: anytype, args: std.meta.ArgsTuple(@TypeOf(function))) void {
const Args = @TypeOf(args);
const TypeErased = struct {
fn start(context: *const anyopaque) void {
const args_casted: *const Args = @ptrCast(@alignCast(context));
_ = @as(Cancelable!void, @call(.auto, function, args_casted.*)) catch {};
}
};
io.vtable.groupAsync(io.userdata, g, @ptrCast(&args), .of(Args), TypeErased.start);
}
/// Equivalent to `Io.concurrent`, except the task is spawned in this
/// `Group` instead of becoming associated with a `Future`.
///
/// The return type of `function` must be coercible to `Cancelable!void`.
/// `function` returning `error.Canceled` does nothing because it is an
/// cancelation propagation boundary.
///
/// Once this function is called, there are resources associated with the
/// group. To release those resources, `Group.await` or `Group.cancel` must
/// eventually be called.
pub fn concurrent(g: *Group, io: Io, function: anytype, args: std.meta.ArgsTuple(@TypeOf(function))) ConcurrentError!void {
const Args = @TypeOf(args);
const TypeErased = struct {
fn start(context: *const anyopaque) void {
const args_casted: *const Args = @ptrCast(@alignCast(context));
_ = @as(Cancelable!void, @call(.auto, function, args_casted.*)) catch {};
}
};
return io.vtable.groupConcurrent(io.userdata, g, @ptrCast(&args), .of(Args), TypeErased.start);
}
/// Blocks until all tasks of the group finish. During this time,
/// cancelation requests propagate to all members of the group, and
/// will also cause `error.Canceled` to be returned when the group
/// does ultimately finish.
///
/// After this function returns, all tasks of the `Group` created with
/// `async` or `concurrent` are guaranteed to have run.
///
/// Idempotent. Not threadsafe.
///
/// It is safe to call this function concurrently with `Group.async` or
/// `Group.concurrent`, provided that the group does not complete until
/// the call to `Group.async` or `Group.concurrent` returns.
pub fn await(g: *Group, io: Io) Cancelable!void {
const token = g.token.load(.acquire) orelse return;
try io.vtable.groupAwait(io.userdata, g, token);
assert(g.token.raw == null);
}
/// Equivalent to `await` but immediately requests cancelation on all
/// members of the group.
///
/// After this function returns, all tasks of the `Group` created with
/// `async` or `concurrent` are guaranteed to have run.
///
/// For a description of cancelation and cancelation points, see `Future.cancel`.
///
/// Idempotent. Not threadsafe.
///
/// It is safe to call this function concurrently with `Group.async` or
/// `Group.concurrent`, provided that the group does not complete until
/// the call to `Group.async` or `Group.concurrent` returns.
pub fn cancel(g: *Group, io: Io) void {
const token = g.token.load(.acquire) orelse return;
io.vtable.groupCancel(io.userdata, g, token);
assert(g.token.raw == null);
}
}
An unordered set of tasks which can only be awaited or canceled as a whole. Tasks are spawned in the group with
Group.asyncandGroup.concurrent.The resources associated with each task are guaranteed to be released when the individual task returns, as opposed to when the whole group completes or is awaited. For this reason, it is not a resource leak to have a long-lived group which concurrent tasks are repeatedly added to. However, asynchronous tasks are not guaranteed to run until
Group.awaitorGroup.cancelis called, so adding async tasks to a group without ever awaiting it may leak resources.