I'm writing an audio synthesiser and want to use the cpal
crate to output audio. That happens by spawning an output thread, whose "data generation" function needs to implement FnMut(&mut [T], &OutputCallbackInfo) + Send + 'static
. The OutputCallbackInfo
is irrelevant to the question at hand.
To generate the audio, I have an AudioPipeline
struct:
pub struct AudioPipeline {
producer: Box<dyn AudioProducer + Sync>,
modifiers: Vec<Box<dyn AudioModifier + Sync>>,
}
where AudioProducer
and AudioModifier
are some other traits. In main
, I create such a pipeline, and then send it over to spawned thread using a moving closure:
let pipeline = AudioPipeline::new(Box::new(sine), vec![Box::new(asdr)]);
let stream = device
.build_output_stream(
...
move |data: &mut [u8], callback_info: &cpal::OutputCallbackInfo| {
...
pipeline.recv();
...
},
...
);
Here, pipeline.recv()
is a method on AudioPipeline
that takes &mut self
.
The code doesn't compile, giving me this error instead:
(dyn AudioProducer + Sync + 'static) cannot be sent between threads safely
the trait bound Unique<(dyn AudioProducer + Sync + 'static)>: Send is not satisfied
required for Unique<(dyn AudioProducer + Sync + 'static)> to implement Send
I gather that the issue has something to do with using Box
? But I find this error a bit hard to grasp: after all, the docs explicitly say "[Unique<T>
] implements Send
/Sync
if T
is Send
/Sync
." Surely by requiring that the dyn AudioProducer
is also Sync
, it should definitely be Send
, right? I'm probably missing some thread-safe subtelty here.
Sync
does not imply Send
.
They are related but its not like Sync
is a sub type of Send
or anything like that. There are types that are Send + !Sync
and others that are Sync + !Send
; they each have their own meanings.
So your trait object needs to be specified Send + Sync
- very common in multi-threaded code.