mirror of
https://github.com/ziglang/zig.git
synced 2025-12-06 14:23:09 +00:00
while still preserving the guarantee about async() being assigned a unit of concurrency (or immediately running the task), this change: * retains the error from calling getCpuCount() * spawns all threads in detached mode, using WaitGroup to join them * treats all workers the same regardless of whether they are processing concurrent or async tasks. one thread pool does all the work, while respecting async and concurrent limits.
132 lines
4.0 KiB
Zig
132 lines
4.0 KiB
Zig
const builtin = @import("builtin");
|
|
|
|
const std = @import("std");
|
|
const Io = std.Io;
|
|
const testing = std.testing;
|
|
const assert = std.debug.assert;
|
|
|
|
test "concurrent vs main prevents deadlock via oversubscription" {
|
|
var threaded: Io.Threaded = .init(std.testing.allocator);
|
|
defer threaded.deinit();
|
|
const io = threaded.io();
|
|
|
|
threaded.async_limit = .nothing;
|
|
|
|
var queue: Io.Queue(u8) = .init(&.{});
|
|
|
|
var putter = io.concurrent(put, .{ io, &queue }) catch |err| switch (err) {
|
|
error.ConcurrencyUnavailable => {
|
|
try testing.expect(builtin.single_threaded);
|
|
return;
|
|
},
|
|
};
|
|
defer putter.cancel(io);
|
|
|
|
try testing.expectEqual(42, queue.getOneUncancelable(io));
|
|
}
|
|
|
|
fn put(io: Io, queue: *Io.Queue(u8)) void {
|
|
queue.putOneUncancelable(io, 42);
|
|
}
|
|
|
|
fn get(io: Io, queue: *Io.Queue(u8)) void {
|
|
assert(queue.getOneUncancelable(io) == 42);
|
|
}
|
|
|
|
test "concurrent vs concurrent prevents deadlock via oversubscription" {
|
|
var threaded: Io.Threaded = .init(std.testing.allocator);
|
|
defer threaded.deinit();
|
|
const io = threaded.io();
|
|
|
|
threaded.async_limit = .nothing;
|
|
|
|
var queue: Io.Queue(u8) = .init(&.{});
|
|
|
|
var putter = io.concurrent(put, .{ io, &queue }) catch |err| switch (err) {
|
|
error.ConcurrencyUnavailable => {
|
|
try testing.expect(builtin.single_threaded);
|
|
return;
|
|
},
|
|
};
|
|
defer putter.cancel(io);
|
|
|
|
var getter = try io.concurrent(get, .{ io, &queue });
|
|
defer getter.cancel(io);
|
|
|
|
getter.await(io);
|
|
putter.await(io);
|
|
}
|
|
|
|
const ByteArray256 = struct { x: [32]u8 align(32) };
|
|
const ByteArray512 = struct { x: [64]u8 align(64) };
|
|
|
|
fn concatByteArrays(a: ByteArray256, b: ByteArray256) ByteArray512 {
|
|
return .{ .x = a.x ++ b.x };
|
|
}
|
|
|
|
test "async/concurrent context and result alignment" {
|
|
var buffer: [2048]u8 align(@alignOf(ByteArray512)) = undefined;
|
|
var fba: std.heap.FixedBufferAllocator = .init(&buffer);
|
|
|
|
var threaded: std.Io.Threaded = .init(fba.allocator());
|
|
defer threaded.deinit();
|
|
const io = threaded.io();
|
|
|
|
const a: ByteArray256 = .{ .x = @splat(2) };
|
|
const b: ByteArray256 = .{ .x = @splat(3) };
|
|
const expected: ByteArray512 = .{ .x = @as([32]u8, @splat(2)) ++ @as([32]u8, @splat(3)) };
|
|
|
|
{
|
|
var future = io.async(concatByteArrays, .{ a, b });
|
|
const result = future.await(io);
|
|
try std.testing.expectEqualSlices(u8, &expected.x, &result.x);
|
|
}
|
|
{
|
|
var future = io.concurrent(concatByteArrays, .{ a, b }) catch |err| switch (err) {
|
|
error.ConcurrencyUnavailable => {
|
|
try testing.expect(builtin.single_threaded);
|
|
return;
|
|
},
|
|
};
|
|
const result = future.await(io);
|
|
try std.testing.expectEqualSlices(u8, &expected.x, &result.x);
|
|
}
|
|
}
|
|
|
|
fn concatByteArraysResultPtr(a: ByteArray256, b: ByteArray256, result: *ByteArray512) void {
|
|
result.* = .{ .x = a.x ++ b.x };
|
|
}
|
|
|
|
test "Group.async context alignment" {
|
|
var buffer: [2048]u8 align(@alignOf(ByteArray512)) = undefined;
|
|
var fba: std.heap.FixedBufferAllocator = .init(&buffer);
|
|
|
|
var threaded: std.Io.Threaded = .init(fba.allocator());
|
|
defer threaded.deinit();
|
|
const io = threaded.io();
|
|
|
|
const a: ByteArray256 = .{ .x = @splat(2) };
|
|
const b: ByteArray256 = .{ .x = @splat(3) };
|
|
const expected: ByteArray512 = .{ .x = @as([32]u8, @splat(2)) ++ @as([32]u8, @splat(3)) };
|
|
|
|
var group: std.Io.Group = .init;
|
|
var result: ByteArray512 = undefined;
|
|
group.async(io, concatByteArraysResultPtr, .{ a, b, &result });
|
|
group.wait(io);
|
|
try std.testing.expectEqualSlices(u8, &expected.x, &result.x);
|
|
}
|
|
|
|
fn returnArray() [32]u8 {
|
|
return @splat(5);
|
|
}
|
|
|
|
test "async with array return type" {
|
|
var threaded: std.Io.Threaded = .init(std.testing.allocator);
|
|
defer threaded.deinit();
|
|
const io = threaded.io();
|
|
|
|
var future = io.async(returnArray, .{});
|
|
const result = future.await(io);
|
|
try std.testing.expectEqualSlices(u8, &@as([32]u8, @splat(5)), &result);
|
|
}
|