# Julia 1.7 says it can switch the thread your task is on. How often does that happen, and how can it be disabled?

**URL:** <https://discourse.julialang.org/t/julia-1-7-says-it-can-switch-the-thread-your-task-is-on-how-often-does-that-happen-and-how-can-it-be-disabled/75373>\
**Category:** General Usage\
**Tags:** task, threads\
**Created:** [January 28, 2022, 2:54pm UTC](https://discourse.julialang.org/t/julia-1-7-says-it-can-switch-the-thread-your-task-is-on-how-often-does-that-happen-and-how-can-it-be-disabled/75373 "2022-01-28T14:54:14Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![heyx3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heyx3/32/29811_2.png) [@heyx3](https://discourse.julialang.org/u/heyx3)\
**Post date:** [January 28, 2022, 2:54pm UTC](https://discourse.julialang.org/t/julia-1-7-says-it-can-switch-the-thread-your-task-is-on-how-often-does-that-happen-and-how-can-it-be-disabled/75373/1 "2022-01-28T14:54:14Z")

</div>

According to the release notes:

> Tasks can now migrate among threads when they are re-scheduled. Previously, a Task would always run on whichever thread executed it first

Does this mean that the thread I’m running on can no longer be controlled? I was working on an OpenGL project, and OpenGL requires that all calls essentially happen on a single thread, so if I can’t depend on my task staying on the same thread anymore, then it’s virtually impossible to write OpenGL code in Julia.

---

<div class="post-metadata">

**Author:** ![Oscar\_Smith](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/oscar_smith/32/25343_2.png) [@Oscar\_Smith](https://discourse.julialang.org/u/Oscar_Smith)\
**Post date:** [January 28, 2022, 2:57pm UTC](https://discourse.julialang.org/t/julia-1-7-says-it-can-switch-the-thread-your-task-is-on-how-often-does-that-happen-and-how-can-it-be-disabled/75373/2 "2022-01-28T14:57:46Z")

</div>

See [Thread affinitization: pinning Julia threads to cores - #5 by carstenbauer](https://discourse.julialang.org/t/thread-affinitization-pinning-julia-threads-to-cores/58069/5)

---

<div class="post-metadata">

**Author:** ![heyx3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heyx3/32/29811_2.png) [@heyx3](https://discourse.julialang.org/u/heyx3)\
**Post date:** [January 28, 2022, 3:06pm UTC](https://discourse.julialang.org/t/julia-1-7-says-it-can-switch-the-thread-your-task-is-on-how-often-does-that-happen-and-how-can-it-be-disabled/75373/3 "2022-01-28T15:06:39Z")

</div>

That discussion leads to a package, ThreadPinning.jl, which only supports Linux.

Is there really no standard way to do this? That seems like a serious regression; OpenGL isn’t the only un-thread-safe C library…

---

<div class="post-metadata">

**Author:** ![carstenbauer](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/carstenbauer/32/4981_2.png) [@carstenbauer](https://discourse.julialang.org/u/carstenbauer)\
**Post date:** [January 28, 2022, 3:44pm UTC](https://discourse.julialang.org/t/julia-1-7-says-it-can-switch-the-thread-your-task-is-on-how-often-does-that-happen-and-how-can-it-be-disabled/75373/4 "2022-01-28T15:44:30Z")

</div>

Let’s not confuse threads with tasks here. Primarily, ThreadPinning.jl is for pinning Julia threads to specific cores. That’s it. Whether tasks are started on and/or stay on a certain Julia thread is an entirely different thing.

> [@heyx3](#):
>
> Does this mean that the thread I’m running on can no longer be controlled?

First things first: Julia implements task-based multithreading (somewhat similar to Go), so the general idea is that users care about tasks and not so much about threads. You just `@spawn` whatever you want and let the scheduler put this on a certain thread or, if necessary, let the task migrate to another thread if necessary. In some sense, this is great since it abstracts away some of the more low-level scheduling aspects and also facilitates composable / nested multithreading.  
However, sometimes you want / need to control on which Julia thread (and, if pinned to a core in some way, which core) a task runs on. The good news is, this is still possible (see below). However, I must say that my feeling is that it is not really supported since it might undermine the idea of composable task-based multithreading (personally, I think we should support both!).

So, how can we “pin” a task to a certain Julia thread? The keyword here is `sticky`. If you look at the source code of `@threads` (in particular [this function](https://github.com/JuliaLang/julia/blob/a25f128a8fc38eb86f1067316509838d29c8c007/base/threadingconstructs.jl#L25)), you see that the task(s) corresponding to the body of the multithreaded loop will get [put on specific threads](https://github.com/JuliaLang/julia/blob/a25f128a8fc38eb86f1067316509838d29c8c007/base/threadingconstructs.jl#L32) and, importantly, get the property [`sticky = true`](https://github.com/JuliaLang/julia/blob/a25f128a8fc38eb86f1067316509838d29c8c007/base/threadingconstructs.jl#L31). This means, that the task will stay on this Julia thread and won’t migrate away. So, if you write a loop like

```julia
@threads for i in 1:nthreads()
    f(i)
end

```

you can be sure that `f(i)` will run on the Julia thread `i` and will stay there. Contrast this to `@spawn` which has [`sticky = false`](https://github.com/JuliaLang/julia/blob/a25f128a8fc38eb86f1067316509838d29c8c007/base/threadingconstructs.jl#L183). Hence, tasks spawned in that way can, in principle, migrate between threads.

Now you might say, well that’s great but I sometimes want to “spawn” a single task on a specific thread… While you could use `@threads` for this,

```julia
@threads for i in 1:nthreads()
    if i == thread_that_should_run_the_computation
        f()
    end
end

```

this is arguably overly complex and also somewhat of a misuse of `@threads`. Fortunately, we can essentially just define our own hybrid of `@threads` and `@spawn` with `sticky = true`. That’s what [`@tspawnat`](https://github.com/carstenbauer/ThreadPinning.jl/blob/main/src/helper.jl#L189) is which I’ve added to ThreadPinning.jl yesterday (note that ThreadPools.jl also has a `@tspawnat` but, counterintuitively, it has `sticky = false`, see [this issue](https://github.com/tro3/ThreadPools.jl/issues/32)). So, you can now just do

```julia
using ThreadPinning
t = @tspawnat 3 f()
[...]
fetch(t)

```

to run `f()` on the third Julia thread without any task migration.

(Note that while the thread pinning part of ThreadPinning.jl only supports Linux, `@tspawnat` can, of course, be used on any system since it is only about making Julia tasks sticky.)

---

<div class="post-metadata">

**Author:** ![heyx3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heyx3/32/29811_2.png) [@heyx3](https://discourse.julialang.org/u/heyx3)\
**Post date:** [January 28, 2022, 4:17pm UTC](https://discourse.julialang.org/t/julia-1-7-says-it-can-switch-the-thread-your-task-is-on-how-often-does-that-happen-and-how-can-it-be-disabled/75373/5 "2022-01-28T16:17:28Z")

</div>

Thank you for the detailed explanation!

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [January 28, 2022, 4:27pm UTC](https://discourse.julialang.org/t/julia-1-7-says-it-can-switch-the-thread-your-task-is-on-how-often-does-that-happen-and-how-can-it-be-disabled/75373/6 "2022-01-28T16:27:50Z")

</div>

> [@heyx3](#):
>
> requires that all calls essentially happen on a single thread

Isn’t it really that you can’t call OpenGL from multiple threads at once? Does it really know which OS thread it’s being called from? I mean, I suppose it might create some kind of thread local storage or something… but usually it’d just mean that you can’t have multiple threads calling it at once. When a task switches from one julia thread to another it’s still a single thread at a time that is calling the OpenGL code.

---

<div class="post-metadata">

**Author:** ![heyx3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/heyx3/32/29811_2.png) [@heyx3](https://discourse.julialang.org/u/heyx3)\
**Post date:** [January 28, 2022, 5:01pm UTC](https://discourse.julialang.org/t/julia-1-7-says-it-can-switch-the-thread-your-task-is-on-how-often-does-that-happen-and-how-can-it-be-disabled/75373/7 "2022-01-28T17:01:19Z")

</div>

An OpenGL “context” is attached to a specific thread, acting as a thread-local singleton. You can detach and reattach it to another thread, but it’s not a trivial process and certainly not something you want to have to constantly check for.
