diff --git a/base/threadingconstructs.jl b/base/threadingconstructs.jl index 6cc538c4b2ec4..a5b87939f5d95 100644 --- a/base/threadingconstructs.jl +++ b/base/threadingconstructs.jl @@ -8,6 +8,11 @@ export threadid, nthreads, @threads, @spawn, Get the ID number of the current thread of execution. The master thread has ID `1`. + +!!! note + The thread that a task runs on may change if the task yields, which is known as [`Task Migration`](@ref man-task-migration). + For this reason in most cases it is not safe to use `threadid()` to index into, say, a vector of buffer or stateful objects. + """ threadid() = Int(ccall(:jl_threadid, Int16, ())+1) @@ -208,7 +213,7 @@ For example, the above conditions imply that: - Write only to locations not shared across iterations (unless a lock or atomic operation is used). - The value of [`threadid()`](@ref Threads.threadid) may change even within a single - iteration. + iteration. See [`Task Migration`](@ref man-task-migration) ## Schedulers @@ -334,8 +339,10 @@ the _value_ of a variable, isolating the asynchronous code from changes to the variable's value in the current task. !!! note - See the manual chapter on [multi-threading](@ref man-multithreading) - for important caveats. See also the chapter on [threadpools](@ref man-threadpools). + The thread that the task runs on may change if the task yields, therefore `threadid()` should not + be treated as constant for a task. See [`Task Migration`](@ref man-task-migration), and the broader + [multi-threading](@ref man-multithreading) manual for further important caveats. + See also the chapter on [threadpools](@ref man-threadpools). !!! compat "Julia 1.3" This macro is available as of Julia 1.3. diff --git a/doc/src/manual/multi-threading.md b/doc/src/manual/multi-threading.md index b012de27ac81f..c5c084fe4f1ef 100644 --- a/doc/src/manual/multi-threading.md +++ b/doc/src/manual/multi-threading.md @@ -372,6 +372,18 @@ threads in Julia: This may require some transitional work across the ecosystem before threading can be widely adopted with confidence. See the next section for further details. +## [Task Migration](@id man-task-migration) + +After a task starts running on a certain thread (e.g. via [`@spawn`](@ref Threads.@spawn) or +[`@threads`](@ref Threads.@threads)), it may move to a different thread if the task yields. + +This means that [`threadid()`](@ref Threads.threadid) should not be treated as constant within a task, and therefore +should not be used to index into a vector of buffers or stateful objects. + +!!! compat "Julia 1.7" + Task migration was introduced in Julia 1.7. Before this tasks always remained on the same thread that they were + started on. + ## Safe use of Finalizers Because finalizers can interrupt any code, they must be very careful in how