Merge pull request #8097 from LemonBoy/thread-spawn-order
std: Swap arguments in Thread.spawn
This commit is contained in:
@@ -933,8 +933,8 @@ const assert = std.debug.assert;
|
||||
threadlocal var x: i32 = 1234;
|
||||
|
||||
test "thread local storage" {
|
||||
const thread1 = try std.Thread.spawn({}, testTls);
|
||||
const thread2 = try std.Thread.spawn({}, testTls);
|
||||
const thread1 = try std.Thread.spawn(testTls, {});
|
||||
const thread2 = try std.Thread.spawn(testTls, {});
|
||||
testTls({});
|
||||
thread1.wait();
|
||||
thread2.wait();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user