diff --git a/base/threadingconstructs.jl b/base/threadingconstructs.jl index 714a7054313d0..a59c0046dd07b 100644 --- a/base/threadingconstructs.jl +++ b/base/threadingconstructs.jl @@ -22,6 +22,11 @@ julia> Threads.@threads for i in 1:4 5 4 ``` + +!!! 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) @@ -229,7 +234,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 @@ -355,8 +360,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 be64390e473f2..afb1c749f9447 100644 --- a/doc/src/manual/multi-threading.md +++ b/doc/src/manual/multi-threading.md @@ -388,6 +388,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