Следующий код воспроизводит ту же проблему (предполагая, что Engine
сохраняет только AndroidAudioIO
на уровне типа, так что он может создать такой обработчик на более позднем этапе; он также работает с помощью прямой композиции).
#[macro_use]
extern crate lazy_static;
use std::marker::PhantomData;
use std::ptr::NonNull;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct SLObjectItf;
pub struct AndroidAudioIO {
sl_output_buffer_queue: NonNull<SLObjectItf>,
}
unsafe impl Send for AndroidAudioIO {}
#[derive(Debug)]
pub struct Engine<T>(PhantomData<T>);
lazy_static! {
static ref engine: Option<Engine<AndroidAudioIO>> = None;
}
( Playground )
Проблема здесь в том, что эта сущность Engine
находится в глобальной статической переменной, которая немедленно делает ее общей для всех потоков.Для этого требуется Sync
, но Engine
не была предоставлена реализация Sync
, поскольку AudioAndroidIO
не реализует Sync
.Действительно, независимо от того, содержит ли движок обработчик ввода-вывода аудио в качестве атрибута или эта информация существует только на уровне типа, даже PhantomData
наследует эти реализации признака непосредственно от своего типа параметра.Цитирование из документов:
impl<T: ?Sized> Send for PhantomData<T>
where
T: Send,
impl<T: ?Sized> Sync for PhantomData<T>
where
T: Sync
Вероятно, это тот случай, когда Engine
можно иметь Sync
(хотя PhantomData
выбирает это безопасное поведение, избегая предположений о внутреннем типе).Чтобы решить эту проблему, сначала убедитесь, что absolute уверен, что Engine
является потокобезопасным.Затем вручную добавьте Sync
для этого.
unsafe impl<T> Sync for Engine<T> {}
Я попытался добавить unsafe impl Send for SLObjectItf_{}
и другие варианты безрезультатно.
Ну,это вообще было бы Плохой Идеей ™ так или иначе.Реализация Send
и / или Sync
должна выполняться поверх безопасной высокоуровневой абстракции ваших привязок.