mirror of
https://github.com/ziglang/zig.git
synced 2024-11-16 17:15:37 +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,
|
Unexpected,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// caller must call wait on the returned thread
|
// Given `T`, the type of the thread startFn, extract the expected type for the
|
||||||
/// fn startFn(@TypeOf(context)) T
|
// context parameter.
|
||||||
/// where T is u8, noreturn, void, or !void
|
fn SpawnContextType(comptime T: type) type {
|
||||||
/// caller must call wait on the returned thread
|
const TI = @typeInfo(T);
|
||||||
pub fn spawn(context: anytype, comptime startFn: anytype) SpawnError!*Thread {
|
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");
|
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
|
// TODO compile-time call graph analysis to determine stack upper bound
|
||||||
// https://github.com/ziglang/zig/issues/157
|
// https://github.com/ziglang/zig/issues/157
|
||||||
const default_stack_size = 16 * 1024 * 1024;
|
const default_stack_size = 16 * 1024 * 1024;
|
||||||
|
|
||||||
const Context = @TypeOf(context);
|
const Context = @TypeOf(context);
|
||||||
comptime assert(@typeInfo(@TypeOf(startFn)).Fn.args[0].arg_type.? == Context);
|
|
||||||
|
|
||||||
if (std.Target.current.os.tag == .windows) {
|
if (std.Target.current.os.tag == .windows) {
|
||||||
const WinThread = struct {
|
const WinThread = struct {
|
||||||
|
@ -220,8 +220,8 @@ test "basic usage" {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var context = Context{};
|
var context = Context{};
|
||||||
const send_thread = try std.Thread.spawn(&context, Context.sender);
|
const send_thread = try std.Thread.spawn(Context.sender, &context);
|
||||||
const recv_thread = try std.Thread.spawn(&context, Context.receiver);
|
const recv_thread = try std.Thread.spawn(Context.receiver, &context);
|
||||||
|
|
||||||
send_thread.wait();
|
send_thread.wait();
|
||||||
recv_thread.wait();
|
recv_thread.wait();
|
||||||
|
@ -299,7 +299,7 @@ test "basic usage" {
|
|||||||
const thread_count = 10;
|
const thread_count = 10;
|
||||||
var threads: [thread_count]*std.Thread = undefined;
|
var threads: [thread_count]*std.Thread = undefined;
|
||||||
for (threads) |*t| {
|
for (threads) |*t| {
|
||||||
t.* = try std.Thread.spawn(&context, worker);
|
t.* = try std.Thread.spawn(worker, &context);
|
||||||
}
|
}
|
||||||
for (threads) |t|
|
for (threads) |t|
|
||||||
t.wait();
|
t.wait();
|
||||||
|
@ -281,7 +281,7 @@ test "basic usage" {
|
|||||||
var context: Context = undefined;
|
var context: Context = undefined;
|
||||||
try context.init();
|
try context.init();
|
||||||
defer context.deinit();
|
defer context.deinit();
|
||||||
const receiver = try std.Thread.spawn(&context, Context.receiver);
|
const receiver = try std.Thread.spawn(Context.receiver, &context);
|
||||||
defer receiver.wait();
|
defer receiver.wait();
|
||||||
context.sender();
|
context.sender();
|
||||||
|
|
||||||
@ -290,7 +290,7 @@ test "basic usage" {
|
|||||||
// https://github.com/ziglang/zig/issues/7009
|
// https://github.com/ziglang/zig/issues/7009
|
||||||
var timed = Context.init();
|
var timed = Context.init();
|
||||||
defer timed.deinit();
|
defer timed.deinit();
|
||||||
const sleeper = try std.Thread.spawn(&timed, Context.sleeper);
|
const sleeper = try std.Thread.spawn(Context.sleeper, &timed);
|
||||||
defer sleeper.wait();
|
defer sleeper.wait();
|
||||||
try timed.timedWaiter();
|
try timed.timedWaiter();
|
||||||
}
|
}
|
||||||
|
@ -379,7 +379,7 @@ test "basic usage" {
|
|||||||
};
|
};
|
||||||
|
|
||||||
var context = Context{};
|
var context = Context{};
|
||||||
const receiver = try std.Thread.spawn(&context, Context.receiver);
|
const receiver = try std.Thread.spawn(Context.receiver, &context);
|
||||||
defer receiver.wait();
|
defer receiver.wait();
|
||||||
context.sender();
|
context.sender();
|
||||||
|
|
||||||
@ -388,7 +388,7 @@ test "basic usage" {
|
|||||||
// https://github.com/ziglang/zig/issues/7009
|
// https://github.com/ziglang/zig/issues/7009
|
||||||
var timed = Context.init();
|
var timed = Context.init();
|
||||||
defer timed.deinit();
|
defer timed.deinit();
|
||||||
const sleeper = try std.Thread.spawn(&timed, Context.sleeper);
|
const sleeper = try std.Thread.spawn(Context.sleeper, &timed);
|
||||||
defer sleeper.wait();
|
defer sleeper.wait();
|
||||||
try timed.timedWaiter();
|
try timed.timedWaiter();
|
||||||
}
|
}
|
||||||
|
@ -216,11 +216,11 @@ test "std.atomic.Queue" {
|
|||||||
|
|
||||||
var putters: [put_thread_count]*std.Thread = undefined;
|
var putters: [put_thread_count]*std.Thread = undefined;
|
||||||
for (putters) |*t| {
|
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;
|
var getters: [put_thread_count]*std.Thread = undefined;
|
||||||
for (getters) |*t| {
|
for (getters) |*t| {
|
||||||
t.* = try std.Thread.spawn(&context, startGets);
|
t.* = try std.Thread.spawn(startGets, &context);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (putters) |t|
|
for (putters) |t|
|
||||||
|
@ -123,11 +123,11 @@ test "std.atomic.stack" {
|
|||||||
} else {
|
} else {
|
||||||
var putters: [put_thread_count]*std.Thread = undefined;
|
var putters: [put_thread_count]*std.Thread = undefined;
|
||||||
for (putters) |*t| {
|
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;
|
var getters: [put_thread_count]*std.Thread = undefined;
|
||||||
for (getters) |*t| {
|
for (getters) |*t| {
|
||||||
t.* = try std.Thread.spawn(&context, startGets);
|
t.* = try std.Thread.spawn(startGets, &context);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (putters) |t|
|
for (putters) |t|
|
||||||
|
@ -185,7 +185,7 @@ pub const Loop = struct {
|
|||||||
errdefer self.deinitOsData();
|
errdefer self.deinitOsData();
|
||||||
|
|
||||||
if (!builtin.single_threaded) {
|
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) {
|
errdefer if (!builtin.single_threaded) {
|
||||||
self.posixFsRequest(&self.fs_end_request);
|
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) {
|
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 => {
|
.macos, .freebsd, .netbsd, .dragonfly, .openbsd => {
|
||||||
@ -329,7 +329,7 @@ pub const Loop = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
|
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 => {
|
.windows => {
|
||||||
@ -378,7 +378,7 @@ pub const Loop = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
while (extra_thread_index < extra_thread_count) : (extra_thread_index += 1) {
|
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 => {},
|
else => {},
|
||||||
@ -798,7 +798,7 @@ pub const Loop = struct {
|
|||||||
.event = std.Thread.AutoResetEvent{},
|
.event = std.Thread.AutoResetEvent{},
|
||||||
.is_running = true,
|
.is_running = true,
|
||||||
// Must be last so that it can read the other state, such as `is_running`.
|
// 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();
|
try evt.init();
|
||||||
defer evt.deinit();
|
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();
|
defer t.wait();
|
||||||
|
|
||||||
const SLEEP_TIMEOUT_NS = 10 * std.time.ns_per_ms;
|
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();
|
defer t.wait();
|
||||||
|
|
||||||
var client = try server.accept();
|
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();
|
defer t.wait();
|
||||||
|
|
||||||
var client = try server.accept();
|
var client = try server.accept();
|
||||||
|
@ -59,11 +59,11 @@ test "Once executes its function just once" {
|
|||||||
defer for (threads) |handle| handle.wait();
|
defer for (threads) |handle| handle.wait();
|
||||||
|
|
||||||
for (threads) |*handle| {
|
for (threads) |*handle| {
|
||||||
handle.* = try std.Thread.spawn(@as(u8, 0), struct {
|
handle.* = try std.Thread.spawn(struct {
|
||||||
fn thread_fn(x: u8) void {
|
fn thread_fn(x: u8) void {
|
||||||
global_once.call();
|
global_once.call();
|
||||||
}
|
}
|
||||||
}.thread_fn);
|
}.thread_fn, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -317,7 +317,7 @@ test "std.Thread.getCurrentId" {
|
|||||||
if (builtin.single_threaded) return error.SkipZigTest;
|
if (builtin.single_threaded) return error.SkipZigTest;
|
||||||
|
|
||||||
var thread_current_id: Thread.Id = undefined;
|
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();
|
const thread_id = thread.handle();
|
||||||
thread.wait();
|
thread.wait();
|
||||||
if (Thread.use_pthreads) {
|
if (Thread.use_pthreads) {
|
||||||
@ -336,10 +336,10 @@ test "spawn threads" {
|
|||||||
|
|
||||||
var shared_ctx: i32 = 1;
|
var shared_ctx: i32 = 1;
|
||||||
|
|
||||||
const thread1 = try Thread.spawn({}, start1);
|
const thread1 = try Thread.spawn(start1, {});
|
||||||
const thread2 = try Thread.spawn(&shared_ctx, start2);
|
const thread2 = try Thread.spawn(start2, &shared_ctx);
|
||||||
const thread3 = try Thread.spawn(&shared_ctx, start2);
|
const thread3 = try Thread.spawn(start2, &shared_ctx);
|
||||||
const thread4 = try Thread.spawn(&shared_ctx, start2);
|
const thread4 = try Thread.spawn(start2, &shared_ctx);
|
||||||
|
|
||||||
thread1.wait();
|
thread1.wait();
|
||||||
thread2.wait();
|
thread2.wait();
|
||||||
@ -367,8 +367,8 @@ test "cpu count" {
|
|||||||
|
|
||||||
test "thread local storage" {
|
test "thread local storage" {
|
||||||
if (builtin.single_threaded) return error.SkipZigTest;
|
if (builtin.single_threaded) return error.SkipZigTest;
|
||||||
const thread1 = try Thread.spawn({}, testTls);
|
const thread1 = try Thread.spawn(testTls, {});
|
||||||
const thread2 = try Thread.spawn({}, testTls);
|
const thread2 = try Thread.spawn(testTls, {});
|
||||||
testTls({});
|
testTls({});
|
||||||
thread1.wait();
|
thread1.wait();
|
||||||
thread2.wait();
|
thread2.wait();
|
||||||
|
@ -74,7 +74,7 @@ pub fn init(self: *ThreadPool, allocator: *std.mem.Allocator) !void {
|
|||||||
try worker.idle_node.data.init();
|
try worker.idle_node.data.init();
|
||||||
errdefer worker.idle_node.data.deinit();
|
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