mirror of
https://github.com/ziglang/zig.git
synced 2024-11-16 09:03:12 +00:00
std: Swap arguments in Thread.spawn
Beside the new order being consistent with the ThreadPool API and making more sense, this shuffling allows to write the context argument type in terms of the startFn arguments, reducing the use of anytype (eg. less explicit casts when using comptime_int parameters, yay). Sorry for the breakage. Closes #8082
This commit is contained in:
parent
e65b6d99ac
commit
566adc2510
@ -165,18 +165,32 @@ pub const SpawnError = error{
|
||||
Unexpected,
|
||||
};
|
||||
|
||||
/// caller must call wait on the returned thread
|
||||
/// fn startFn(@TypeOf(context)) T
|
||||
/// where T is u8, noreturn, void, or !void
|
||||
/// caller must call wait on the returned thread
|
||||
pub fn spawn(context: anytype, comptime startFn: anytype) SpawnError!*Thread {
|
||||
// Given `T`, the type of the thread startFn, extract the expected type for the
|
||||
// context parameter.
|
||||
fn SpawnContextType(comptime T: type) type {
|
||||
const TI = @typeInfo(T);
|
||||
if (TI != .Fn)
|
||||
@compileError("expected function type, found " ++ @typeName(T));
|
||||
|
||||
if (TI.Fn.args.len != 1)
|
||||
@compileError("expected function with single argument, found " ++ @typeName(T));
|
||||
|
||||
return TI.Fn.args[0].arg_type orelse
|
||||
@compileError("cannot use a generic function as thread startFn");
|
||||
}
|
||||
|
||||
/// Spawns a new thread executing startFn, returning an handle for it.
|
||||
/// Caller must call wait on the returned thread.
|
||||
/// The `startFn` function must take a single argument of type T and return a
|
||||
/// value of type u8, noreturn, void or !void.
|
||||
/// The `context` parameter is of type T and is passed to the spawned thread.
|
||||
pub fn spawn(comptime startFn: anytype, context: SpawnContextType(@TypeOf(startFn))) SpawnError!*Thread {
|
||||
if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");
|
||||
// TODO compile-time call graph analysis to determine stack upper bound
|
||||
// https://github.com/ziglang/zig/issues/157
|
||||
const default_stack_size = 16 * 1024 * 1024;
|
||||
|
||||
const Context = @TypeOf(context);
|
||||
comptime assert(@typeInfo(@TypeOf(startFn)).Fn.args[0].arg_type.? == Context);
|
||||
|
||||
if (std.Target.current.os.tag == .windows) {
|
||||
const WinThread = struct {
|
||||
|
@ -220,8 +220,8 @@ test "basic usage" {
|
||||
};
|
||||
|
||||
var context = Context{};
|
||||
const send_thread = try std.Thread.spawn(&context, Context.sender);
|
||||
const recv_thread = try std.Thread.spawn(&context, Context.receiver);
|
||||
const send_thread = try std.Thread.spawn(Context.sender, &context);
|
||||
const recv_thread = try std.Thread.spawn(Context.receiver, &context);
|
||||
|
||||
send_thread.wait();
|
||||
recv_thread.wait();
|
||||
|
@ -299,7 +299,7 @@ test "basic usage" {
|
||||
const thread_count = 10;
|
||||
var threads: [thread_count]*std.Thread = undefined;
|
||||
for (threads) |*t| {
|
||||
t.* = try std.Thread.spawn(&context, worker);
|
||||
t.* = try std.Thread.spawn(worker, &context);
|
||||
}
|
||||
for (threads) |t|
|
||||
t.wait();
|
||||
|
@ -281,7 +281,7 @@ test "basic usage" {
|
||||
var context: Context = undefined;
|
||||
try context.init();
|
||||
defer context.deinit();
|
||||
const receiver = try std.Thread.spawn(&context, Context.receiver);
|
||||
const receiver = try std.Thread.spawn(Context.receiver, &context);
|
||||
defer receiver.wait();
|
||||
context.sender();
|
||||
|
||||
@ -290,7 +290,7 @@ test "basic usage" {
|
||||
// https://github.com/ziglang/zig/issues/7009
|
||||
var timed = Context.init();
|
||||
defer timed.deinit();
|
||||
const sleeper = try std.Thread.spawn(&timed, Context.sleeper);
|
||||
const sleeper = try std.Thread.spawn(Context.sleeper, &timed);
|
||||
defer sleeper.wait();
|
||||
try timed.timedWaiter();
|
||||
}
|
||||
|
@ -379,7 +379,7 @@ test "basic usage" {
|
||||
};
|
||||
|
||||
var context = Context{};
|
||||
const receiver = try std.Thread.spawn(&context, Context.receiver);
|
||||
const receiver = try std.Thread.spawn(Context.receiver, &context);
|
||||
defer receiver.wait();
|
||||
context.sender();
|
||||
|
||||
@ -388,7 +388,7 @@ test "basic usage" {
|
||||
// https://github.com/ziglang/zig/issues/7009
|
||||
var timed = Context.init();
|
||||
defer timed.deinit();
|
||||
const sleeper = try std.Thread.spawn(&timed, Context.sleeper);
|
||||
const sleeper = try std.Thread.spawn(Context.sleeper, &timed);
|
||||
defer sleeper.wait();
|
||||
try timed.timedWaiter();
|
||||
}
|
||||
|
@ -216,11 +216,11 @@ test "std.atomic.Queue" {
|
||||
|
||||
var putters: [put_thread_count]*std.Thread = undefined;
|
||||
for (putters) |*t| {
|
||||
t.* = try std.Thread.spawn(&context, startPuts);
|
||||
t.* = try std.Thread.spawn(startPuts, &context);
|
||||
}
|
||||
var getters: [put_thread_count]*std.Thread = undefined;
|
||||
for (getters) |*t| {
|
||||
t.* = try std.Thread.spawn(&context, startGets);
|
||||
t.* = try std.Thread.spawn(startGets, &context);
|
||||
}
|
||||
|
||||
for (putters) |t|
|
||||
|
@ -123,11 +123,11 @@ test "std.atomic.stack" {
|
||||
} else {
|
||||
var putters: [put_thread_count]*std.Thread = undefined;
|
||||
for (putters) |*t| {
|
||||
t.* = try std.Thread.spawn(&context, startPuts);
|
||||
t.* = try std.Thread.spawn(startPuts, &context);
|
||||
}
|
||||
var getters: [put_thread_count]*std.Thread = undefined;
|
||||
for (getters) |*t| {
|
||||
t.* = try std.Thread.spawn(&context, startGets);
|
||||
t.* = try std.Thread.spawn(startGets, &context);
|
||||
}
|
||||
|
||||
for (putters) |t|
|
||||
|
@ -185,7 +185,7 @@ pub const Loop = struct {
|
||||
errdefer self.deinitOsData();
|
||||
|
||||
if (!builtin.single_threaded) {
|
||||
self.fs_thread = try Thread.spawn(self, posixFsRun);
|
||||
self.fs_thread = try Thread.spawn(posixFsRun, self);
|
||||
}
|
||||
errdefer if (!builtin.single_threaded) {
|
||||
self.posixFsRequest(&self.fs_end_request);
|
||||
@ -264,7 +264,7 @@ pub const Loop = struct {
|
||||
}
|
||||
}
|
||||
while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
|
||||
self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
|
||||
self.extra_threads[extra_thread_index] = try Thread.spawn(workerRun, self);
|
||||
}
|
||||
},
|
||||
.macos, .freebsd, .netbsd, .dragonfly, .openbsd => {
|
||||
@ -329,7 +329,7 @@ pub const Loop = struct {
|
||||
}
|
||||
}
|
||||
while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
|
||||
self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
|
||||
self.extra_threads[extra_thread_index] = try Thread.spawn(workerRun, self);
|
||||
}
|
||||
},
|
||||
.windows => {
|
||||
@ -378,7 +378,7 @@ pub const Loop = struct {
|
||||
}
|
||||
}
|
||||
while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
|
||||
self.extra_threads[extra_thread_index] = try Thread.spawn(self, workerRun);
|
||||
self.extra_threads[extra_thread_index] = try Thread.spawn(workerRun, self);
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
@ -798,7 +798,7 @@ pub const Loop = struct {
|
||||
.event = std.Thread.AutoResetEvent{},
|
||||
.is_running = true,
|
||||
// Must be last so that it can read the other state, such as `is_running`.
|
||||
.thread = try std.Thread.spawn(self, DelayQueue.run),
|
||||
.thread = try std.Thread.spawn(DelayQueue.run, self),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -762,7 +762,7 @@ test "open file with exclusive lock twice, make sure it waits" {
|
||||
try evt.init();
|
||||
defer evt.deinit();
|
||||
|
||||
const t = try std.Thread.spawn(S.C{ .dir = &tmp.dir, .evt = &evt }, S.checkFn);
|
||||
const t = try std.Thread.spawn(S.checkFn, S.C{ .dir = &tmp.dir, .evt = &evt });
|
||||
defer t.wait();
|
||||
|
||||
const SLEEP_TIMEOUT_NS = 10 * std.time.ns_per_ms;
|
||||
|
@ -161,7 +161,7 @@ test "listen on a port, send bytes, receive bytes" {
|
||||
}
|
||||
};
|
||||
|
||||
const t = try std.Thread.spawn(server.listen_address, S.clientFn);
|
||||
const t = try std.Thread.spawn(S.clientFn, server.listen_address);
|
||||
defer t.wait();
|
||||
|
||||
var client = try server.accept();
|
||||
@ -285,7 +285,7 @@ test "listen on a unix socket, send bytes, receive bytes" {
|
||||
}
|
||||
};
|
||||
|
||||
const t = try std.Thread.spawn({}, S.clientFn);
|
||||
const t = try std.Thread.spawn(S.clientFn, {});
|
||||
defer t.wait();
|
||||
|
||||
var client = try server.accept();
|
||||
|
@ -59,11 +59,11 @@ test "Once executes its function just once" {
|
||||
defer for (threads) |handle| handle.wait();
|
||||
|
||||
for (threads) |*handle| {
|
||||
handle.* = try std.Thread.spawn(@as(u8, 0), struct {
|
||||
handle.* = try std.Thread.spawn(struct {
|
||||
fn thread_fn(x: u8) void {
|
||||
global_once.call();
|
||||
}
|
||||
}.thread_fn);
|
||||
}.thread_fn, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -317,7 +317,7 @@ test "std.Thread.getCurrentId" {
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
|
||||
var thread_current_id: Thread.Id = undefined;
|
||||
const thread = try Thread.spawn(&thread_current_id, testThreadIdFn);
|
||||
const thread = try Thread.spawn(testThreadIdFn, &thread_current_id);
|
||||
const thread_id = thread.handle();
|
||||
thread.wait();
|
||||
if (Thread.use_pthreads) {
|
||||
@ -336,10 +336,10 @@ test "spawn threads" {
|
||||
|
||||
var shared_ctx: i32 = 1;
|
||||
|
||||
const thread1 = try Thread.spawn({}, start1);
|
||||
const thread2 = try Thread.spawn(&shared_ctx, start2);
|
||||
const thread3 = try Thread.spawn(&shared_ctx, start2);
|
||||
const thread4 = try Thread.spawn(&shared_ctx, start2);
|
||||
const thread1 = try Thread.spawn(start1, {});
|
||||
const thread2 = try Thread.spawn(start2, &shared_ctx);
|
||||
const thread3 = try Thread.spawn(start2, &shared_ctx);
|
||||
const thread4 = try Thread.spawn(start2, &shared_ctx);
|
||||
|
||||
thread1.wait();
|
||||
thread2.wait();
|
||||
@ -367,8 +367,8 @@ test "cpu count" {
|
||||
|
||||
test "thread local storage" {
|
||||
if (builtin.single_threaded) return error.SkipZigTest;
|
||||
const thread1 = try Thread.spawn({}, testTls);
|
||||
const thread2 = try Thread.spawn({}, testTls);
|
||||
const thread1 = try Thread.spawn(testTls, {});
|
||||
const thread2 = try Thread.spawn(testTls, {});
|
||||
testTls({});
|
||||
thread1.wait();
|
||||
thread2.wait();
|
||||
|
@ -74,7 +74,7 @@ pub fn init(self: *ThreadPool, allocator: *std.mem.Allocator) !void {
|
||||
try worker.idle_node.data.init();
|
||||
errdefer worker.idle_node.data.deinit();
|
||||
|
||||
worker.thread = try std.Thread.spawn(worker, Worker.run);
|
||||
worker.thread = try std.Thread.spawn(Worker.run, worker);
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user