-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Description
Is your feature request related to a problem? Please describe.
The current (as of 1.47.1) documentation of tokio::task::Id
guarantees very little. I wonder if I'm missing something, but it seems to guarantee so little that there's no safe way to utilize it in user code. In particular, I'm concerned about task ID re-use. Consider the following code:
use tokio::task::{Id, JoinSet};
let join_set = JoinSet::new();
let my_map: HashMap<Id, u32> = HashMap::new();
let first = join_set.spawn(async move {}).id();
my_map.insert(first, 42);
// Let's say the spawned task exits at this point. Could its task ID get reclaimed?
let second = join_set.spawn(async move {}).id();
if let Some(_existing) = my_map.insert(second, 7) {
panic!("Duplicate entry might happen?");
}
The current set of guarantees doesn't seem to forbid the first task's ID being re-used for the second, as it only guarantees uniqueness amongst "currently running tasks". If a task ID is released as soon as the function passed to spawn()
returns, user code ends up with no real control over the uniqueness of IDs, preventing them from being useful.
Describe the solution you'd like
I believe the only viable solution is to have tasks prevent re-use of their ID until the function passed to spawn()
completes, and that task is either joined or detached.
The PR adding IDs was motivated by the ability for user code to create a JoinMap
, which has a similar problem of having to associate IDs with specific tasks, and would run into similar issues if reuse-before-join was allowed to happen. In particular, this comment:
I thought that the guarantees offered by using an address would be sufficient for implementing a JoinMap and similar things, given that the task is not deallocated until its output is consumed
seems to confirm that we need to provide this guarantee. We can do this without sacrificing other guarantees - it would be upheld whether the ID was sequentially generated like it is now, or based on the task's address like it seems to originally have been.
Therefore, I think we should change When a task completes, the same ID may be used for another task.
to When a task completes, and is joined or detached, the same ID may be used for another task.
No code changes would be needed, as the current implementation provides this already.
Describe alternatives you've considered
We could go all the way and guarantee sequential IDs, but I don't yet see a motivation to do so. Although the linked PR switched to sequential IDs for the implementation, it doesn't seem to provide a concrete counterexample to using task addresses.