That’s more of a question for the task locals pitch semantics, but let’s quickly address it...
It isn’t about the task, it is about the specific fields and their storage.
As I mentioned, reading canceled status is safe since it’s just an atomic load of an atomic status integer in the task. Other more complex operations on the task may not be safe — that’s it.
Access to task-locals outside of the task is racy semantically (if it is executing, and entering/exiting withLocal blocks, those are mutating the bound values stack — so it is racy what value you’d observe from outside of the task), as well as “weird” (why the hell would you do that) so we don’t allow for it.
Sure, it can be made thread-safe (by using a treiber stack (simple lock free stack)), but we don’t have to since logically we don’t want to allow external access anyway, so why would we. It does not make sense to read them outside the task from arbitrary other tasks — so we can avoid synchronization there, making accesses to the locals cheaper. Perhaps we’ll do the lockfree stack anyway, but it does not make sense to me to allow “arbitrary random task can read your task locals” and we should not do this.
For the implementation on how it’s stored, you can refer to the task locals PR which contains a full implementation along with many docs explaining it.