bevyengine / bevyengine/bevy

Parallel runner deadlocks with idling threads in ComputeTaskPool

Open
#4,161 7 comments 0 reactions 0 assignees View on GitHub
A-Tasks C-Bug
Dominant language
Rust
Stars
48.2k
Forks
4.8k
Avg merge
3d 16h
Merged PRs (30d)
171

Description

## Bevy version

0.6.0

## Operating system & version

Windows 11

## What you did

```rs
let mut app = App::new();

app.insert_resource(bevy_tasks::ComputeTaskPool(
bevy_tasks::TaskPoolBuilder::new().num_threads(1).build(),
));

let a = Arc::new(FairMutex::new(0usize));
let b = Arc::new(FairMutex::new(0usize));
let c = Arc::new(FairMutex::new(0usize));

let set = SystemSet::new()
.with_system({
let a = Arc::clone(&a);
(move || {
tracing::info!(
thread_id = format_args!("{:?}", std::thread::current()),
"A incrementing"
);
*a.lock() += 1;
})
})
.with_system({
let b = Arc::clone(&b);
(move || {
tracing::info!(
thread_id = format_args!("{:?}", std::thread::current()),
"B incrementing"
);
*b.lock() += 1;
})
})
.with_system(
(move || {
tracing::info!(thread_id = format_args!("{:?}", std::thread::current()), "C spinning");
let mut c = c.lock();
*c += 1;
while *a.lock() != *c || *b.lock() != *c {}
}),
);

app.add_system_set_to_stage(CoreStage::Update, set);

for ix in 0..500 {
let _span = tracing::info_span!("iteration", ix).entered();
app.update();
}

```

## What you expected to happen

With the main thread + one more thread in the task pool, this should be completeable regardless of execution order.

## What actually happened

It deadlocks after a number of iterations, here's a snapshot of the tracing logs (only the last entries):

```
...

2022-03-09T00:54:16.833550Z INFO repro: C spinning, thread_id: Thread { id: ThreadId(1), name: Some("main"), .. }
at src/main.rs:123
in bevy_ecs::schedule::executor_parallel::system with name: "repro::main::{{closure}}"
in bevy_ecs::schedule::executor_parallel::prepare_systems
in bevy_ecs::schedule::stage with name: Update
in repro::iteration with ix: 182

2022-03-09T00:54:16.833562Z INFO repro: A incrementing, thread_id: Thread { id: ThreadId(2), name: Some("TaskPool (0)"), .. }
at src/main.rs:104
in bevy_ecs::schedule::executor_parallel::system with name: "repro::main::{{closure}}"
in bevy_ecs::schedule::executor_parallel::prepare_systems
in bevy_ecs::schedule::stage with name: Update
in repro::iteration with ix: 182

2022-03-09T00:54:16.834361Z INFO repro: B incrementing, thread_id: Thread { id: ThreadId(2), name: Some("TaskPool (0)"), .. }
at src/main.rs:114
in bevy_ecs::schedule::executor_parallel::system with name: "repro::main::{{closure}}"
in bevy_ecs::schedule::executor_parallel::prepare_systems
in bevy_ecs::schedule::stage with name: Update
in repro::iteration with ix: 182

2022-03-09T00:54:16.835071Z INFO repro: B incrementing, thread_id: Thread { id: ThreadId(1), name: Some("main"), .. }
at src/main.rs:114
in bevy_ecs::schedule::executor_parallel::system with name: "repro::main::{{closure}}"
in bevy_ecs::schedule::executor_parallel::prepare_systems
in bevy_ecs::schedule::stage with name: Update
in repro::iteration with ix: 183

2022-03-09T00:54:16.835076Z INFO repro: C spinning, thread_id: Thread { id: ThreadId(2), name: Some("TaskPool (0)"), .. }
at src/main.rs:123
in bevy_ecs::schedule::executor_parallel::system with name: "repro::main::{{closure}}"
in bevy_ecs::schedule::executor_parallel::prepare_systems
in bevy_ecs::schedule::stage with name: Update
in repro::iteration with ix: 183
```

These logs show a successful iteration (there were 181 more before it), followed by a deadlock which I exited out after waiting a couple of seconds.

Contributor guide

Open the contributing guide

Research direction

Reproduce the one-thread ComputeTaskPool case using the TaskPoolBuilder setup in the issue, then inspect the bevy_ecs::schedule::executor_parallel path named in the trace. Compare the successful and deadlocking iterations and add a regression test if the relevant test location becomes clear. Done means the 500 updates complete without deadlocking.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
distributed-systems, game-dev
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.