From e569fbc50ee4822016a7eb03ad3893a9cc414539 Mon Sep 17 00:00:00 2001 From: NetterSilver <133535268+Silvertree2010@users.noreply.github.com> Date: Sat, 24 Oct 2026 03:53:05 +0000 Subject: [PATCH] Render strips serially on the audio thread instead of using rayon Fixes #886 Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 Co-Authored-By: Claude Haiku 5.5 Co-Authored-By: Claude Sonnet 5.5 --- crates/mix/src/threads.rs | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-) diff --git a/crates/mix/src/threads.rs b/crates/mix/src/threads.rs index c71fb3fc..f3e34b69 100644 --- a/crates/mix/src/threads.rs +++ b/crates/mix/src/threads.rs @@ -33,10 +33,10 @@ fn as_audio_thread(audio: bool, f: impl FnOnce()) { #[cfg(not(target_arch = "wasm32"))] pub(crate) fn run_strips(work: &mut [T], f: impl Fn(&mut T) + Sync + Send) { use rayon::prelude::*; - if work.len() >= 4 { - // The workers render on behalf of this thread: on the audio thread, they are it too. - let audio = on_audio_thread(); - work.par_iter_mut().for_each(|w| as_audio_thread(audio, || f(w))); + // The audio thread is not a rayon worker, so it would park on a latch waiting for the shared + // pool (also busy with offline work): it renders its strips itself. + if work.len() >= 4 && !on_audio_thread() { + work.par_iter_mut().for_each(|w| as_audio_thread(false, || f(w))); } else { work.iter_mut().for_each(f); } @@ -86,7 +86,23 @@ mod audio_thread_tests { #[test] fn strips_rendered_for_the_audio_thread_count_as_the_audio_thread_and_only_then() { - assert!(seen_by_strips(true).iter().all(|&rt| rt), "a worker rendering for the audio thread is on it"); + assert!(seen_by_strips(true).iter().all(|&rt| rt), "strips rendered for the audio thread are on it"); assert!(seen_by_strips(false).iter().all(|&rt| !rt), "the workers don't stay marked afterwards"); } + + #[test] + fn the_audio_thread_never_hands_strips_to_the_rayon_pool() { + let on_pool = std::thread::spawn(|| { + mark_audio_thread(); + let mut work = vec![false; 8]; + run_strips(&mut work, |w| { + std::thread::sleep(std::time::Duration::from_millis(1)); + *w = rayon::current_thread_index().is_some(); + }); + work.into_iter().filter(|&p| p).count() + }) + .join() + .unwrap(); + assert_eq!(on_pool, 0, "the audio thread must not block on the rayon pool"); + } }